quantities.h
Go to the documentation of this file.
1 /**
2  * @file lardataalg/Utilities/quantities.h
3  * @brief Numeric variable proxies with embedded unit of measurement.
4  * @author Gianluca Petrillo (petrillo@slac.stanford.edu)
5  * @date October 30, 2018
6  * @see lardataalg/Utilities/quantites/spacetime.h
7  *
8  * Infrastructure for a library for variables with a given unit of measurement.
9  *
10  *
11  * Why not `Boost::units`?
12  * ------------------------
13  *
14  * My attempt to use `Boost::units` for the implementation (or directly) failed
15  * because the `quantity` in that library is bound to a dimension without a
16  * prefix modifier, e.g. always represents seconds, while we may need
17  * nanoseconds. Having a type representing a time in nanoseconds is not trivial,
18  * and having two types for representation of time in nanoseconds _and_
19  * microseconds respectively is plain complicate.
20  *
21  * On the converse, that library provides arithmetic which is
22  * checked for dimensionality correctness. That is beyond the scope of this
23  * set of types.
24  *
25  * @note This code is C++17 only.
26  *
27  */
28 
29 #ifndef LARDATAALG_UTILITIES_QUANTITIES_H
30 #define LARDATAALG_UTILITIES_QUANTITIES_H
31 
32 // LArSoft libraries
33 #include "lardataalg/Utilities/constexpr_math.h" // util::abs()
34 #include "larcorealg/CoreUtils/MetaUtils.h" // util::always_true_v<>
35 #include "larcorealg/CoreUtils/StdUtils.h" // util::to_string(), ...
36 
37 // Boost libraries
38 #include "boost/integer/common_factor_rt.hpp" // boost::integer::gcd()
39 
40 // C/C++ standard libraries
41 #include <ostream>
42 #include <map>
43 #include <string>
44 #include <string_view>
45 #include <regex>
46 #include <ratio>
47 #include <limits>
48 #include <functional> // std::hash<>
49 #include <type_traits> // std::is_same<>, std::enable_if_t<>, ...
50 #include <cctype> // std::isblank()
51 
52 
53 /**
54  * @brief Types of variables with a unit.
55  *
56  * This library uses the following concepts, vaguely inspired by Boost Units
57  * library:
58  *
59  * * _dimension_ is a category of measurements, e.g. time; there is no
60  * representation of this concept in this library
61  * * _unit_ is a scale to represent a dimension, e.g. seconds; there is no
62  * * representation for the generic unit concept in this library, but each
63  * * unit needs its own unique class representing it; an example of this
64  * * simple class is `util::quantities::UnitBase`
65  * * _scaled unit_ is a unit with a factor modifying its scale; e.g.,
66  * microsecond; this is represented in this library as `ScaledUnit`
67  * * _quantity_ is a value interpreted via a specific scaled unit, e.g. 12.3
68  * microseconds; this is represented here by the `Quantity` class.
69  *
70  * Differently from Boost Units library, this one does not provide dimensional
71  * analysis (hence the lack of need for the "dimension" concept.
72  *
73  *
74  * Usage examples
75  * ---------------
76  *
77  * The following examples use units of time, whose definitions are actually
78  * provided elsewhere in this library (see
79  * `lardataalg/Utilities/quantites/spacetime.h` and the unit
80  * `util::quantities::units::Second`).
81  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
82  * void drifting(double driftSpace, double driftVelocity) {
83  *
84  * using namespace util::quantities::time_literals; // [1]
85  *
86  * util::quantities::microsecond driftTime
87  * { driftSpace / driftVelocity };
88  *
89  * std::cout << "Drift time: " << driftTime << std::endl; // writes: "xxx us"
90  *
91  * // double the velocity...
92  * driftTime /= 2.0;
93  * std::cout << "halved!! => " << driftTime << std::endl;
94  *
95  * // add 350 ns of offset
96  * driftTime += 0.350; // ERROR!! what is 0.350?
97  * driftTime += 350_ns; // needs [1]; convert to microseconds and adds
98  * std::cout << "delayed! => " << driftTime << std::endl;
99  *
100  * // ...
101  * auto dual = driftTime * 2.0; // dual is still `microsecond`
102  *
103  * double half = driftTime / 2.0; // the result is converted to `double`
104  * // and looses its unit forever
105  *
106  * double lateTime = 500;
107  * driftTime = lateTime; // ERROR! which unit is `lateTime` in?
108  * driftTime = microsecond(lateTime); // assign from `lateTime` us
109  *
110  * } // drifting()
111  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
112  *
113  *
114  *
115  * Organization of the code
116  * -------------------------
117  *
118  * The code of this library is entirely under this namespace
119  * (`util::quantities`). It is organised in a few subspaces:
120  *
121  * * `concepts` contains all the infrastructure for the library, including the
122  * definition of classes representing a unit, a quantity, and more
123  * * `details`: implementation details (users should not bother with them)
124  * * `units` contains the definitions of actual units (e.g. seconds, ampere...)
125  *
126  * The file `lardataalg/Utilities/quantities.h` does not contain the definition
127  * of any actual quantity nor unit. Quantity libraries are expected to include
128  * this header, extend the namespace `units` to include the units they need,
129  * and finally adding the quantites needed directly in this very namespace.
130  *
131  * An example of adding the definition of "ampere":
132  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
133  * #include "lardataalg/Utilities/quantities.h"
134  *
135  * namespace util::quantities {
136  *
137  * namespace units {
138  *
139  * /// Unit of electric current.
140  * struct ampere {
141  * static constexpr auto symbol = "A"sv;
142  * static constexpr auto name = "ampere"sv;
143  * }; // ampere
144  *
145  * } // namespace units
146  *
147  *
148  * /// Type of current stored in ampere.
149  * template <typename T = double>
150  * using ampere_as = concepts::Quantity<concepts::ScaledUnit<units::ampere>, T>;
151  *
152  * /// Type of current stored in ampere, in double precision.
153  * using ampere = ampere_as<>;
154  *
155  * /// Type of current stored in milliampere.
156  * template <typename T = double>
157  * using milliampere_as = concepts::rescale<ampere_as<T>, std::milli>;
158  *
159  * /// Type of current stored in milliampere, in double precision.
160  * using milliampere = milliampere_as<>;
161  *
162  * } // namespace util::quantities
163  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
164  *
165  * @note The suffix `sv` converts the literal string into a `std::string_view`,
166  * which is one of the few string types which can be defined at compile
167  * time (`constexpr`) and have a decently complete interface.
168  *
169  *
170  * Another example may be data size:
171  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
172  * #include "lardataalg/Utilities/quantities.h"
173  *
174  * namespace util::quantities {
175  *
176  * namespace units {
177  *
178  * /// Unit of data size.
179  * struct byte {
180  * static constexpr auto symbol = "B"sv;
181  * static constexpr auto name = "byte"sv;
182  * }; // byte
183  *
184  * } // namespace units
185  *
186  * namespace binary {
187  *
188  * // Prefix for binary 2^20 (1048576).
189  * using mebi = std::ratio<(1U << 20), 1U>;
190  *
191  * } // namespace binary
192  *
193  * /// Type of data size stored bytes.
194  * template <typename T = unsigned long long>
195  * using byte_as = concepts::Quantity<concepts::ScaledUnit<units::byte>, T>;
196  *
197  * /// Type of data size stored bytes, typically in 64 bits.
198  * using byte = byte_as<>;
199  *
200  * /// Type of data size stored in mibibyte.
201  * template <typename T = unsigned long long>
202  * using mebibyte_as = concepts::rescale<byte_as<T>, binary::mebi>;
203  *
204  * /// Type of data size stored in mibibyte, typically in 64 bits.
205  * using mebibyte = mebibyte_as<>;
206  *
207  * } // namespace util::quantities
208  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
209  * This example _mostly works_, with the following exceptions:
210  *
211  * * the prefix is not known to the infrastructure and it will not be printed
212  * (it will show as question marks)
213  * * especially when using an integral base type, a lot of care must be put
214  * in the rounding: for example, 2000000 bytes will be converted into
215  * 1 mebibyte, and if converted back it will show 1048576 bytes.
216  *
217  */
218 namespace util::quantities {
219 
220  /**
221  * @brief Infrastructure for the quantities library.
222  *
223  * The namespace `concepts` contains all the infrastructure for the library,
224  * including the definition of classes representing a unit, a quantity, and
225  * more.
226  */
227  namespace concepts {
228 
229  namespace details {
230 
231  //------------------------------------------------------------------------
232  //--- Ratio metaprogramming
233  //------------------------------------------------------------------------
234  /// Applies the specified `Ratio` to the value in `v`.
235  template <typename Ratio, typename Value>
236  static constexpr auto applyRatioToValue(Value&& v)
237  { return v * Ratio::num / Ratio::den; }
238 
239  template <typename R>
240  struct invert_ratio;
241 
242  template <typename R>
243  using invert_t = typename invert_ratio<R>::type;
244 
245  template <typename R>
247 
248  template <typename R>
250 
251  //------------------------------------------------------------------------
252  //--- Unit-related
253  //------------------------------------------------------------------------
254  /// Trait: `true_type` if `U` is a `ScaledUnit`-based object.
255  template <typename U>
256  struct has_unit;
257 
258  /// Trait: `true` if `U` is a `ScaledUnit`-based object.
259  template <typename U>
260  constexpr bool has_unit_v = has_unit<U>();
261 
262  /// Trait: `true_type` if `Q` is a `Quantity` specialization.
263  template <typename Q>
264  struct is_quantity;
265 
266  /// Trait: `true` if `Q` is a `Quantity` specialization.
267  template <typename Q>
268  constexpr bool is_quantity_v = is_quantity<Q>();
269 
270  /// Trait: `true_type` if `Q` is a `Quantity`-based object.
271  template <typename Q>
272  struct has_quantity;
273 
274  /// Trait: `true` if `Q` is a `Quantity`-based object.
275  template <typename Q>
276  constexpr bool has_quantity_v = has_quantity<Q>();
277 
278 
279  //------------------------------------------------------------------------
280  /// Trait: type of value of `T`: may be `T` or, for objects with units,
281  /// `T::value_t`.
282  template <typename T>
284 
285  /// Type of value of `T`: may be `T` or, for objects with units,
286  /// `T::value_t`.
287  template <typename T>
289 
290 
291  /**
292  * Trait: `true_type` if the type `T` is a value compatible with the value
293  * of `Q`.
294  */
295  template <typename T, typename Q>
297 
298  /// Trait: `true` if the type `T` is compatible with the value of `Q`.
299  template <typename T, typename Q>
300  constexpr bool is_value_compatible_with_v
302 
303 
304  /**
305  * Trait: `true_type` if the value type of `T` is compatible with the one
306  * of `U`.
307  *
308  * Note that this tells that `T` is compatible with `U`, but it may still
309  * leave `U` not compatible with `T` (for example, if the compatibility
310  * criterium were something asymmetric like a non-narrowing conversion).
311  */
312  template <typename T, typename U>
314 
315  /// Trait: `true` if the value type of `T` is compatible with `U`'s.
316  template <typename T, typename U>
317  constexpr bool has_value_compatible_with_v
319 
320 
321  //------------------------------------------------------------------------
322  //--- constexpr string concatenation
323  //------------------------------------------------------------------------
324  // giving up for now; Boost 1.68.0 offers some help, but we don;t use it
325  // yet
326 
327  //------------------------------------------------------------------------
328  template <typename Q>
330 
331 
332  //------------------------------------------------------------------------
333 
334  } // namespace details
335 
336 
337  using namespace std::string_view_literals;
338 
339  //------------------------------------------------------------------------
340  /// A ratio product (like `std::ratio_multiply`) with simplified terms.
341  template <typename ARatio, typename BRatio>
344 
345  /// A ratio division (like `std::ratio_divide`) with simplified terms.
346  template <typename NumRatio, typename DenRatio>
349 
350 
351  //------------------------------------------------------------------------
352  /**
353  * A unit is the definition of a reference quantity to measure a dimension.
354  * For example, second or ampere.
355  *
356  * Units are independent C++ classes which are required to present a minimal
357  * interface:
358  *
359  * * `symbol` of the unit, as a static constant string
360  * * `name` of the unit, as a static constant string
361  *
362  * Here "string" is intended as an object convertible to `std::string` and
363  * which itself exposes a `std::string`-like behaviour.
364  *
365  * Although units can be derived from `UnitBase`, there is currently no
366  * necessity to do so since no part is shared.
367  * `UnitBase` is therefore provided as an example implementation.
368  */
369  struct UnitBase {
370  /// Symbol of the unit (e.g. "A").
371  static constexpr std::string_view symbol = "?"sv;
372  /// Long name of unit (e.g. "ampere").
373  static constexpr std::string_view name = "unknown"sv;
374  }; // struct UnitBase
375 
376 
377  template <typename R>
378  struct Prefix {
379  using ratio = R; ///< The ratio this prefix is about.
380 
381  /// Returns the unit symbol (`Long` `false`) or name (`Long` `true`).
382  static constexpr auto names(bool Long = false);
383 
384  /// Returns the symbol of the prefix.
385  static constexpr auto symbol() { return names(false); }
386 
387  /// Returns the full name of the prefix.
388  static constexpr auto name() { return names(true); }
389 
390  }; // struct Prefix
391 
392 
393  template <typename U, typename R = std::ratio<1>>
394  struct ScaledUnit {
395 
396  using baseunit_t = U; ///< Base, unscaled unit.
397  using unit_t = ScaledUnit<U, R>; ///< Unit with scale (i.e. this object).
398  using ratio = R; ///< The ratio to go from the base unit to this one.
399  using prefix_t = Prefix<ratio>; ///< The prefix of the unit.
400 
401 
402  // -- BEGIN Conversion to string -----------------------------------------
403  /**
404  * @name Conversion to string.
405  *
406  * @note Implementation note: the returned values (currently
407  * `std::string_view`) are not `constexpr` since it takes noticeable
408  * additional effort to make them so.
409  */
410  /// @{
411 
412  /// Returns short symbol of the unit (e.g. "ns") is a string-like object.
413  static auto symbol()
414  { return std::string(prefix().symbol()) + baseUnit().symbol.data(); }
415 
416  /// Returns full name of the unit (e.g. "nanoseconds") as a string-like
417  /// object.
418  static auto name()
419  { return std::string(prefix().name()) + baseUnit().name.data(); }
420 
421  /// @}
422  // -- END Conversion to string -------------------------------------------
423 
424 
425  // -- BEGIN Representation conversions -----------------------------------
426  /// @{
427  /// @name Representation conversions.
428 
429  /// Converts a value from the base unit to this one.
430  template <typename T>
431  static constexpr T scale(T v)
432  { return details::applyRatioToValue<details::invert_t<ratio>>(v); }
433 
434  /// Converts a value from this scaled unit to the base one.
435  template <typename T>
436  static constexpr T unscale(T v)
437  { return details::applyRatioToValue<ratio>(v); }
438 
439  /// Converts a value from the scaled unit to a different `TargetRatio`.
440  template <typename TargetRatio, typename T>
441  static constexpr T scaleTo(T v)
442  {
445  }
446 
447  /// Converts a value from `TargetRatio` scale to this scaled unit.
448  template <typename TargetRatio, typename T>
449  static constexpr T fromRepr(T v)
450  {
453  }
454 
455  /// @}
456  // -- END Representation conversions -------------------------------------
457 
458  // -- BEGIN Type features ------------------------------------------------
459  /// @name Type features
460  /// @{
461 
462  /// Returns an instance of the `prefix_t` type.
463  static constexpr prefix_t prefix() { return {}; }
464 
465  /// Returns an instance of the `baseunit_t` type.
466  static constexpr baseunit_t baseUnit() { return {}; }
467 
468  /// Returns an instance of the `unit_t` type.
469  static constexpr unit_t unit() { return {}; }
470 
471  /// Returns whether scaled unit `U` has the same base unit as this one.
472  template <typename OU>
473  static constexpr bool sameBaseUnitAs()
474  { return std::is_same<baseunit_t, typename OU::baseunit_t>(); }
475 
476  /// Returns whether scaled unit `U` has the same base unit as this one.
477  template <typename OU>
478  static constexpr bool sameUnitAs()
479  { return std::is_same<unit_t, typename OU::unit_t>(); }
480 
481  /// @}
482  // -- END Type features --------------------------------------------------
483 
484  }; // ScaledUnit<>
485 
486 
487  template <typename U, typename R>
488  std::ostream& operator<< (std::ostream& out, ScaledUnit<U, R> const& unit)
489  {
490  using unit_t = ScaledUnit<U, R>;
491  return out << unit_t::prefix_t::symbol() << unit_t::baseunit_t::symbol;
492  }
493 
494 
495  /** ************************************************************************
496  * @brief A value measured in the specified unit.
497  * @tparam Unit the scaled unit type representing the unit of this quantity
498  * @tparam T type of base value
499  *
500  * A `Quantity` instance is a glorified number of type `T` (or, `value_t`).
501  * The `Quantity` class adds to it the explicit documentation of the unit
502  * the value is measured in, plus some attempt to preserve that information:
503  *
504  * * a `Quantity` type will carry the information of its unit with the type
505  * * quantities must be assigned other quantities:
506  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
507  * using util::quantities::milliampere;
508  *
509  * milliampere i;
510  * i = 2.5; // ERROR! what is 2.5?
511  * i = milliampere(2.5);
512  *
513  * milliampere i2 { 2.5 }; // SPECIAL, allowed only in construction
514  * i2 = i1;
515  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
516  * * can be converted, implicitly or explicitly, to its plain value:
517  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
518  * using util::quantities::milliampere;
519  *
520  * milliampere i { 6.0 };
521  * double v = i; // implicit conversion
522  * v = double(i); // explicit conversion
523  * v = i.value(); // even more explicit conversion
524  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
525  * * weakly resists attempts to mess with units
526  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
527  * milliampere mi { 4.0 };
528  * microampere ui { 500.0 };
529  * mi = ui; // now mi == 0.5
530  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
531  * * weakly attempts to preserve the unit information
532  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
533  * using namespace util::quantities;
534  * using namespace util::quantities::electronics_literals;
535  *
536  * milliampere mi { 4.0 };
537  * microampere ui { 500.0 };
538  *
539  * mi += ui; // 4.5 mA
540  * mi *= ui; // ERROR! what does this even mean??
541  * mi += 5.0; // ERROR!
542  * mi += milliampere(3.0); // 7.5 mA
543  * mi += 2.0_ma; // 9.5 mA
544  * mi + ui; // ERROR! (arbitrary whether to represent in mA or uA)
545  * mi + 5.0; // ERROR! (as above)
546  * mi / 5.0; // milliampere{1.9}
547  * mi - 5_mA; // milliampere{4.5}
548  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
549  *
550  * (`milliampere` and `microampere` are hypotetical instantiations of
551  * `Quantity` template class from `util::quantities`, and they also have
552  * a literal conversion to correctly interpret things like `2.0_ma` or
553  * `7_A`)
554  *
555  *
556  * Implementation details
557  * -----------------------
558  *
559  * * method signatures usually pass `Quantity` objects by value; it is
560  * assumed that the type `T` is simple enough that copying it is faster
561  * than passing around its reference, and that any overhead is
562  * optimized out by the compiler
563  *
564  */
565  template <typename Unit, typename T = double>
566  struct Quantity {
567 
568  public:
569 
570  using value_t = T; ///< Type of the stored value.
571  using unit_t = Unit; ///< The unit and scale of this quantity.
572  using quantity_t = Quantity<Unit, T>; ///< The type of this class.
573 
574  /// Description of the unscaled unit.
575  using baseunit_t = typename unit_t::baseunit_t;
576 
577 
578  /// Constructor: value is left uninitialized.
579  // NOTE: this is not `constexpr` because using it n a constexpr would
580  // yield an uninitialized constant
581  explicit Quantity() = default;
582 
583  /// Constructor: takes a value in the intended representation.
584  explicit constexpr Quantity(value_t v): fValue(v) {}
585 
586  /**
587  * @brief Constructor: converts from another quantity.
588  * @tparam Q type of the other quantity
589  * @param q quantity to be converted from
590  *
591  * Quantities are required to be in the same unit (unit scale may differ).
592  * The value in `q` is converted from its native scale into the one of
593  * this quantity.
594  */
595  template <
596  typename Q,
597  typename std::enable_if_t<details::is_quantity_v<Q>>* = nullptr
598  >
599  constexpr Quantity(Q q)
600  : fValue
601  {unit_t::template fromRepr<typename Q::unit_t::ratio>(q.value()) }
602  {
603  static_assert(sameBaseUnitAs<Q>(),
604  "Can't construct from quantity with different base unit"
605  );
606  }
607 
608  /// Returns the value of the quantity.
609  constexpr value_t value() const { return fValue; }
610 
611  /// Explicit conversion to the base quantity.
612  explicit constexpr operator value_t() const
613  { return value(); }
614 
615  // -- BEGIN Asymmetric arithmetic operations -----------------------------
616  /**
617  * @name Asymmetric operand arithmetic operations
618  *
619  * These arithmetic operations take care of preserving the quantity
620  * through them.
621  * Not all possible (or reasonable) operations are supported yet.
622  * Some operations that may be symmetric (like multiplication by a scalar)
623  * are implemented as free functions rather than methods.
624  *
625  * @note These operations are essentially provided by convenience. There
626  * are many cases (corner and not) where the implicit conversion
627  * to the base type kicks in. This implementation does not aim to
628  * _prevent_ that from happening, but requests are welcome to add
629  * features to _allow_ that not to happen, with some care of the
630  * user.
631  *
632  * @note Operators `+` and `-` support only quantity operands of the same
633  * type, and no plain number operand. The rational behind this is
634  * that when writing `a + b` with `a` and `b` two homogeneous
635  * quantities, we expect to be able to use `b + a` as well.
636  * But it `a` and `b` are different types (e.g. one is `second`,
637  * the other is `millisecond`), an arbitrary choice has to be made
638  * on which type the result should be, and having different types
639  * for `a + b` and `b + a` is not acceptable.
640  * If the intention is clear, methods `plus()` and `minus()` are
641  * provided with the understanding that e.g. `a.plus(b)` explicitly
642  * requires the result to be of type `a`.
643  *
644  */
645  /// @{
646 
647  /// Returns a quantity sum of this and `other` (must have same unit).
648  template <typename OU, typename OT>
649  constexpr quantity_t operator+(Quantity<OU, OT> const other) const;
650 
651  /// Returns a quantity difference of this and `other`
652  /// (must have same unit).
653  template <typename OU, typename OT>
654  constexpr quantity_t operator-(Quantity<OU, OT> const other) const;
655 
656  /// Returns a quantity sum of this and `other`.
657  template <typename OU, typename OT>
658  constexpr quantity_t plus(Quantity<OU, OT> const other) const;
659 
660  /// Returns a quantity difference of this and `other`.
661  template <typename OU, typename OT>
662  constexpr quantity_t minus(Quantity<OU, OT> const other) const;
663 
664  /// Division by a quantity, returns a pure number.
665  template <typename OU, typename OT>
666  constexpr value_t operator/ (Quantity<OU, OT> q) const;
667 
668  /// Add the `other` quantity (possibly concerted) to this one.
669  template <typename OU, typename OT>
670  quantity_t& operator+=(Quantity<OU, OT> const other);
671 
672  /// Subtract the `other` quantity (possibly concerted) to this one.
673  template <typename OU, typename OT>
674  quantity_t& operator-=(Quantity<OU, OT> const other);
675 
676  /// Scale this quantity by a factor.
677  template <typename OT>
678  std::enable_if_t<std::is_arithmetic_v<OT>, quantity_t&>
679  operator*=(OT factor) { fValue *= factor; return *this; }
680 
681  /// Scale the quantity dividing it by a quotient.
682  template <typename OT>
683  std::enable_if_t<std::is_arithmetic_v<OT>, quantity_t&>
684  operator/=(OT quot) { fValue /= quot; return *this; }
685 
686  /// Returns a quantity with same value.
687  constexpr quantity_t operator+() const { return quantity_t(value()); }
688 
689  /// Returns a quantity with same value but the sign flipped.
690  constexpr quantity_t operator-() const { return quantity_t(-value()); }
691 
692  /// Returns a quantity with the absolute value of this one.
693  constexpr quantity_t abs() const
694  { return quantity_t(util::abs(value())); }
695 
696  /// @}
697  // -- END Asymmetric arithmetic operations -------------------------------
698 
699 
700  // -- BEGIN Comparisons --------------------------------------------------
701  /**
702  * @name Comparisons.
703  *
704  * Comparisons with plain numbers are managed by implicit conversion.
705  * More care is needed for quantities.
706  * Comparisons between two quantity instances `a` and `b` work this way:
707  * * if `a` and `b` do not have the same unit, they are _not_ comparable
708  * * if `a` and `b` have the same unit, one is converted to the other and
709  * the comparison is performed there
710  * * if `a` and `b` have the same scaled unit, their values are compared
711  * directly
712  *
713  * Value storage types are compared according to C++ rules.
714  *
715  */
716  /// @{
717 
718  template <typename OU, typename OT>
719  constexpr bool operator==(Quantity<OU, OT> const other) const;
720 
721  template <typename OU, typename OT>
722  constexpr bool operator!=(Quantity<OU, OT> const other) const;
723 
724  template <typename OU, typename OT>
725  constexpr bool operator>=(Quantity<OU, OT> const other) const;
726 
727  template <typename OU, typename OT>
728  constexpr bool operator>(Quantity<OU, OT> const other) const;
729 
730  template <typename OU, typename OT>
731  constexpr bool operator<=(Quantity<OU, OT> const other) const;
732 
733  template <typename OU, typename OT>
734  constexpr bool operator<(Quantity<OU, OT> const other) const;
735 
736  /// @}
737  // -- END Asymmetric arithmetic operations -------------------------------
738 
739 
740  // -- BEGIN Access to the scaled unit ------------------------------------
741  /// @name Access to the scaled unit.
742  /// @{
743 
744  /// Returns an object with as type the scaled unit (`unit_t`).
745  static constexpr unit_t unit() { return {}; }
746 
747  /// Returns an object with as type the base unit (`baseunit_t`).
748  static constexpr baseunit_t baseUnit() { return {}; }
749 
750  /// Returns the full name of the unit, in a string-like object.
751  static auto unitName() { return unit_t::name(); }
752 
753  /// Returns the symbol of the unit, in a string-like object.
754  static auto unitSymbol() { return unit_t::symbol(); }
755 
756  /**
757  * @brief Returns whether this quantity has the same base unit as `OU`.
758  * @param OU any type with `baseunit_t` type
759  * (including `ScaledUnit`, `Quantity`, `Interval`...)
760  */
761  template <typename OU>
762  static constexpr bool sameBaseUnitAs()
763  { return unit_t::template sameBaseUnitAs<OU>(); }
764 
765  /**
766  * @brief Returns whether this quantity has same unit and scale as `OU`.
767  * @param OU any type with `unit_t` type
768  * (including `ScaledUnit`, `Quantity`, `Interval`...)
769  */
770  template <typename OU>
771  static constexpr bool sameUnitAs()
772  { return unit_t::template sameUnitAs<OU>(); }
773 
774  /// Whether `U` is a value type compatible with `value_t`.
775  template <typename U>
776  static constexpr bool is_compatible_value_v
777  = details::is_value_compatible_with_v<U, value_t>;
778 
779  /// Whether `U` has (or is) a value type compatible with `value_t`.
780  template <typename U>
781  static constexpr bool has_compatible_value_v
782  = details::has_value_compatible_with_v<U, value_t>;
783 
784  /// Returns whether `U` is a value type compatible with `value_t`.
785  template <typename U>
786  static constexpr bool isCompatibleValue()
787  { return quantity_t::is_compatible_value_v<U>; }
788 
789  /// Returns whether `U` has (or is) a value type compatible with
790  /// `value_t`.
791  template <typename U>
792  static constexpr bool hasCompatibleValue()
793  { return quantity_t::has_compatible_value_v<U>; }
794 
795 
796  /// @}
797  // -- END Access to the scaled unit --------------------------------------
798 
799  /// Convert this quantity into the specified one.
800  template <typename OQ>
801  constexpr OQ convertInto() const { return OQ(*this); }
802 
803 
804  /**
805  * @brief Returns a new quantity initialized with the specified value
806  * @tparam U type to initialize the quantity with
807  * @param value the value to initialize the quantity with
808  * @return a new `Quantity` object initialized with `value`
809  *
810  * The `value` is cast into `value_t` via `static_cast()`.
811  *
812  * Example: be `Tick` a quantity based on an integral value, like
813  * `util::quantities::tick`, and `detClocks` an instance of
814  * `detinfo::DetectorClocks`:
815  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
816  * double const tickDuration = detClocks.OpticalClock().TickPeriod();
817  *
818  * auto const triggerTick
819  * = Tick::castFrom(detClocks.TriggerTime() / tickDuration);
820  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
821  * `triggerTick` will be of type `Tick` and will denote the number of the
822  * tick (0-based) within which `detClocks.TriggerTime()` fell.
823  */
824  template <typename U>
825  static constexpr quantity_t castFrom(U value)
826  { return quantity_t{ static_cast<value_t>(value) }; }
827 
828 
829  private:
830  value_t fValue {}; ///< Stored value.
831 
832  }; // struct Quantity
833 
834  template <typename... Args>
835  std::ostream& operator<< (std::ostream& out, Quantity<Args...> const q)
836  { return out << q.value() << " " << q.unit(); }
837 
838 
839  // -- BEGIN Arithmetic operations ------------------------------------------
840  /**
841  * @name Arithmetic operations on Quantity
842  *
843  * These operations, as well as the ones implemented as member functions,
844  * are provided for convenience.
845  *
846  * Here the symmetric operations are defined, where different operands can
847  * be swapped.
848  *
849  */
850  /// @{
851 
852  //@{
853  /**
854  * Addition and subtraction of a quantity and a plain number are forbidden.
855  *
856  * The rationale is that it is not acceptable to support `position + 2_m`
857  * but not `2_m + position`, and that it is not acceptable to have
858  * `2_m + 50_cm` yield a type different than `50_cm + 2_m` (i.e. should
859  * both return centimeters, or meters?).
860  */
861  template <typename U, typename T>
862  constexpr Quantity<U, T> operator+ (Quantity<U, T> const q, T shift)
863  = delete;
864  template <typename U, typename T>
865  constexpr Quantity<U, T> operator+ (T shift, Quantity<U, T> const q)
866  = delete;
867  template <typename U, typename T>
868  constexpr Quantity<U, T> operator- (Quantity<U, T> const q, T shift)
869  = delete;
870  template <typename U, typename T>
871  constexpr Quantity<U, T> operator- (T shift, Quantity<U, T> const q)
872  = delete;
873  //@}
874 
875  //@{
876  /// Multiplication with a scalar.
877  template <typename U, typename T, typename OT>
878  constexpr
879  std::enable_if_t
880  <Quantity<U, T>::template is_compatible_value_v<OT>, Quantity<U, T>>
881  operator* (Quantity<U, T> const q, OT factor)
882  { return Quantity<U, T>{ q.value() * static_cast<T>(factor) }; }
883  template <typename U, typename T, typename OT>
884  constexpr
885  std::enable_if_t
886  <Quantity<U, T>::template is_compatible_value_v<OT>, Quantity<U, T>>
887  operator* (OT factor, Quantity<U, T> const q)
888  { return q * factor; }
889  //@}
890 
891  //@{
892  /// Multiplication between quantities is forbidden.
893  template <typename AU, typename AT, typename BU, typename BT>
895  -> decltype(std::declval<AT>() * std::declval<BT>())
896  = delete;
897  //@}
898 
899  //@{
900  // Division by a scalar.
901  template <typename U, typename T, typename OT>
902  constexpr
903  std::enable_if_t
904  <Quantity<U, T>::template is_compatible_value_v<OT>, Quantity<U, T>>
906  { return Quantity<U, T>{ q.value() / static_cast<T>(quot) }; }
907  //@}
908 
909  /// @}
910  // -- END Arithmetic operations --------------------------------------------
911 
912 
913  // -------------------------------------------------------------------------
914  /**
915  * @brief Alias for a quantity based on a scaled unit.
916  * @tparam Unit type of unit (unscaled)
917  * @tparam Ratio scale of the unit for this quantity (e.g. `std::milli`)
918  * @tparam T type of value stored
919  */
920  template <typename Unit, typename Ratio, typename T>
922 
923 
924  // -------------------------------------------------------------------------
925  /// Type of a quantity like `Q`, but with a different unit scale `R`.
926  template <typename Q, typename R, typename T = typename Q::value_t>
928 
929 
930  // -------------------------------------------------------------------------
931 
932  //
933  // extensions STL-style
934  // (can't be put in `std` since they are not specializations)
935  //
936 
937  /// Converts a unit into a string.
938  /// @see `util::to_string()`
939  template <typename... Args>
941  {
942  return
943  std::string(unit.prefix().symbol()) + unit.baseUnit().symbol.data();
944  }
945 
946  /// Converts a quantity into a string.
947  /// @see `util::to_string()`
948  template <typename... Args>
950  { return util::to_string(q.value()) + ' ' + util::to_string(q.unit()); }
951 
952 
953  // -------------------------------------------------------------------------
954 
955  } // namespace concepts
956 
957 
958  // ---------------------------------------------------------------------------
959  /**
960  * @brief Definitions of additional prefixes.
961  *
962  * Quantities are based on _scaled_ units, which are units with a scaling
963  * factor.
964  *
965  * Prefixes describe these scaling factors, as a rational number represented
966  * via a fraction. In this library, prefix objects must expose the same
967  * interface as `std::ratio` template.
968  *
969  * The standard ratio classes defined in C++ (e.g. `std::milli`, `std::giga`)
970  * provide most of the needed prefixes.
971  * In this namespace, custom prefixes can be defined.
972  *
973  * A prefix can be associated with its own symbol. In that case, the prefix
974  * should specialize the template `util::quantites::concepts::Prefix` and
975  * provide:
976  *
977  * * static, `constexpr` method for the full name (`name`), e.g. `"milli"`
978  * * static, `constexpr` method for the short name (`symbol`), e.g. `"m"`
979  *
980  * For example, this prefix should work like 1'000, but has its own symbol:
981  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
982  * namespace util::quantities::prefixes {
983  *
984  * struct grant: public std::ratio<1000> {};
985  *
986  * template <>
987  * struct Prefix<grant> {
988  *
989  * /// Returns the symbol of the prefix.
990  * static constexpr auto symbol() { return "k"sv; }
991  *
992  * /// Returns the full name of the prefix.
993  * static constexpr auto name() { return "grant"sv; }
994  *
995  * }; // struct Prefix<grant>
996  *
997  * } // namespace util::quantities::prefixes
998  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
999  * Note however that the current implementation tends to bring back to
1000  * `std::ratio`. Also note that defining an alias, like in
1001  * `using grant = std::ratio<1000>`, is not enough to allow for a different
1002  * symbol.
1003  *
1004  * The namespace also imports the prefixes from C++ standard library for
1005  * convenience.
1006  */
1007  namespace prefixes { // we expect other libraries to fill it
1008 
1009  // ratios imported from C++ standard library:
1010  using
1011  std::atto, std::femto, std::pico, std::nano, std::micro,
1012  std::milli, std::centi, std::deci,
1013  std::deca, std::hecto, std::kilo,
1014  std::mega, std::giga, std::tera, std::peta, std::exa
1015  ;
1016 
1017  } // namespace prefixes
1018 
1019  // ---------------------------------------------------------------------------
1020  /**
1021  * @brief Definitions of actual units.
1022  *
1023  * Units describe a reference quantity to measure a dimension.
1024  * The namespace `units` contains the definitions of actual units (e.g.
1025  * seconds, ampere...)
1026  *
1027  * Each unit is represented by a class. Each class should follow the interface
1028  * of `util::quantities::concepts::UnitBase`, but it does not have to inherit
1029  * from it.
1030  *
1031  * Each unit must provide its name and its symbol (no locale is supported!).
1032  * Example:
1033  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
1034  * namespace util::quantities::units {
1035  *
1036  * /// Unit of data size.
1037  * struct byte {
1038  * static constexpr auto symbol = "B"sv;
1039  * static constexpr auto name = "byte"sv;
1040  * }; // byte
1041  *
1042  * } // namespace util::quantities::units
1043  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1044  */
1045  namespace units {} // we expect other libraries to fill it
1046 
1047 
1048  // -------------------------------------------------------------------------
1049  // @{
1050  /**
1051  * @brief Returns a quantity of the specified type parsed from a string.
1052  * @tparam Quantity the quantity to be returned
1053  * @param s the string to be parsed
1054  * @param unitOptional (default: `false`) whether unit is not required in `s`
1055  * @return a quantity of the specified type parsed from a string
1056  * @throw MissingUnit `s` does not contain the required unit
1057  * @throw ValueError the numerical value in `s` is not parseable
1058  * @throw ExtraCharactersError spurious characters after the numeric value
1059  * (including an unrecognised unit prefix)
1060  *
1061  * A quantity of type `Quantity` is returned, whose value is interpreted from
1062  * the content of `s`. The standard format includes a real number, a space
1063  * and a unit symbol. If `unitOptional` is `false`, that unit is required,
1064  * otherwise it is optional and defaults to the unit and scale in `Quantity`.
1065  * The base unit in `s`, when present, must exactly match the base unit of
1066  * `Quantity`; the scale may differ, in which case the proper conversion is
1067  * applied.
1068  *
1069  * Example:
1070  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
1071  * using namespace util::quantities::time_literals;
1072  * using util::quantities::microsecond;
1073  *
1074  * auto const t = util::quantities::makeQuantity<microsecond>("7 ms");
1075  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1076  * will assign to `t` the value `7000`.
1077  */
1078  template <typename Quantity>
1079  Quantity makeQuantity(std::string_view s, bool unitOptional = false);
1080 
1081  template <typename Quantity>
1082  Quantity makeQuantity(std::string const& s, bool unitOptional = false);
1083 
1084  template <typename Quantity>
1085  Quantity makeQuantity(char const* s, bool unitOptional = false);
1086 
1087  //@}
1088 
1089  // --- BEGIN -- Specific exceptions ------------------------------------------
1090 
1091  /// String representing a quantity has no unit.
1092  struct MissingUnit: std::runtime_error
1093  { using std::runtime_error::runtime_error; };
1094 
1095  /// String representing a quantity has unsupported unit prefix.
1096  struct InvalidUnitPrefix: std::runtime_error
1097  { using std::runtime_error::runtime_error; };
1098 
1099  /// String representing a quantity has incompatible unit.
1100  struct MismatchingUnit: std::runtime_error
1101  { using std::runtime_error::runtime_error; };
1102 
1103  /// String representing a quantity has an invalid number.
1104  struct ValueError: std::runtime_error
1105  { using std::runtime_error::runtime_error; };
1106 
1107  /// String representing a quantity has spurious characters after the number.
1108  struct ExtraCharactersError: std::runtime_error
1109  { using std::runtime_error::runtime_error; };
1110 
1111 
1112  // --- END -- Specific exceptions --------------------------------------------
1113 
1114  // ---------------------------------------------------------------------------
1115 
1116 } // namespace util::quantities
1117 
1118 
1119 
1120 //------------------------------------------------------------------------------
1121 //--- template implementation
1122 //------------------------------------------------------------------------------
1124 
1125  //----------------------------------------------------------------------------
1126  template <std::intmax_t Num, std::intmax_t Den>
1127  struct invert_ratio<std::ratio<Num, Den>>
1128  { using type = std::ratio<Den, Num>; };
1129 
1130 
1131  //----------------------------------------------------------------------------
1132  template <std::intmax_t Num, std::intmax_t Den>
1133  struct ratio_simplifier<std::ratio<Num, Den>> {
1134  static constexpr auto gcd = boost::integer::gcd(Num, Den);
1135  using type = std::ratio<Num / gcd, Den / gcd>;
1136  }; // ratio_simplifier
1137 
1138 
1139  //----------------------------------------------------------------------------
1140  template <typename U, typename Enable = void>
1141  struct has_unit_impl: public std::false_type {};
1142 
1143  template <typename U>
1145  <U, std::enable_if_t<util::always_true_v<typename U::unit_t>>>
1146  : public std::true_type
1147  {};
1148 
1149  template <typename U>
1150  struct has_unit: public has_unit_impl<U> {};
1151 
1152 
1153  //----------------------------------------------------------------------------
1154  template <typename Q>
1155  struct is_quantity: public std::false_type {};
1156 
1157  template <typename... Args>
1158  struct is_quantity<Quantity<Args...>>: public std::true_type {};
1159 
1160 
1161  //----------------------------------------------------------------------------
1162  template <typename Q, typename Enable = void>
1163  struct has_quantity_impl: public std::false_type {};
1164 
1165  template <typename Q>
1167  <Q, std::enable_if_t<util::always_true_v<typename Q::quantity_t>>>
1168  : public std::true_type
1169  {};
1170 
1171  template <typename Q>
1172  struct has_quantity: public has_quantity_impl<Q> {};
1173 
1174 
1175  //----------------------------------------------------------------------------
1176  template <typename T, typename = void>
1178  using type = T;
1179  }; // quantity_value_type
1180 
1181  template <typename T>
1183  T,
1184  std::enable_if_t
1185  <(has_unit_v<T> && util::always_true_v<typename T::value_t>)>
1186  >
1187  {
1188  using type = typename T::value_t;
1189  }; // quantity_value_type_impl<unit>
1190 
1191 
1192  template <typename T>
1194 
1195 
1196  //----------------------------------------------------------------------------
1197  template <typename T, typename Q>
1199  : std::bool_constant<std::is_convertible_v<T, quantity_value_t<Q>>>
1200  {};
1201 
1202  //----------------------------------------------------------------------------
1203  template <typename T, typename U>
1205  : is_value_compatible_with<quantity_value_t<T>, U>
1206  {};
1207 
1208  //----------------------------------------------------------------------------
1209  /// Limits of a quantity are the same as the underlying type.
1210  template <typename Q>
1211  class numeric_limits: public std::numeric_limits<typename Q::value_t> {
1212 
1213  using quantity_t = Q;
1214  using value_traits_t = std::numeric_limits<typename quantity_t::value_t>;
1215 
1216  public:
1217 
1218  static constexpr quantity_t min() noexcept
1219  { return quantity_t{ value_traits_t::min() }; }
1220  static constexpr quantity_t max() noexcept
1221  { return quantity_t{ value_traits_t::max() }; }
1222  static constexpr quantity_t lowest() noexcept
1223  { return quantity_t{ value_traits_t::lowest() }; }
1224  static constexpr quantity_t epsilon() noexcept
1225  { return quantity_t{ value_traits_t::epsilon() }; }
1226  static constexpr quantity_t round_error() noexcept
1227  { return quantity_t{ value_traits_t::round_error() }; }
1228  static constexpr quantity_t infinity() noexcept
1229  { return quantity_t{ value_traits_t::infinity() }; }
1230  static constexpr quantity_t quiet_NaN() noexcept
1231  { return quantity_t{ value_traits_t::quiet_NaN() }; }
1232  static constexpr quantity_t signaling_NaN() noexcept
1233  { return quantity_t{ value_traits_t::signaling_NaN() }; }
1234  static constexpr quantity_t denorm_min() noexcept
1235  { return quantity_t{ value_traits_t::denorm_min() }; }
1236 
1237  }; // numeric_limits<Quantity>
1238 
1239  //----------------------------------------------------------------------------
1240 
1241 } // namespace util::quantities::concepts::details
1242 
1243 
1244 //------------------------------------------------------------------------------
1245 //--- template implementation
1246 //------------------------------------------------------------------------------
1247 //--- util::quantities::concepts::Prefix
1248 //------------------------------------------------------------------------------
1249 template <typename R>
1251  (bool Long /* = false */)
1252 {
1253  if constexpr(std::is_same<ratio, std::tera>())
1254  return Long? "tera"sv: "T"sv;
1255  if constexpr(std::is_same<ratio, std::giga>())
1256  return Long? "giga"sv: "G"sv;
1257  if constexpr(std::is_same<ratio, std::mega>())
1258  return Long? "mega"sv: "M"sv;
1259  if constexpr(std::is_same<ratio, std::kilo>())
1260  return Long? "kilo"sv: "k"sv;
1261  if constexpr(std::is_same<ratio, std::ratio<1>>())
1262  return ""sv;
1263  if constexpr(std::is_same<ratio, std::deci>())
1264  return Long? "deci"sv: "d"sv;
1265  if constexpr(std::is_same<ratio, std::centi>())
1266  return Long? "centi"sv: "c"sv;
1267  if constexpr(std::is_same<ratio, std::milli>())
1268  return Long? "milli"sv: "m"sv;
1269  if constexpr(std::is_same<ratio, std::micro>())
1270  return Long? "micro"sv: "u"sv;
1271  if constexpr(std::is_same<ratio, std::nano>())
1272  return Long? "nano"sv: "n"sv;
1273  if constexpr(std::is_same<ratio, std::pico>())
1274  return Long? "pico"sv: "p"sv;
1275  if constexpr(std::is_same<ratio, std::femto>())
1276  return Long? "femto"sv: "f"sv;
1277  // TODO complete the long list of prefixes
1278 
1279  // backup; can't use `to_string()` because of `constexpr` requirement
1280  return Long? "???"sv: "?"sv;
1281 } // util::quantities::concepts::Prefix<R>::names()
1282 
1283 
1284 //------------------------------------------------------------------------------
1285 //--- util::quantities::concepts::Quantity
1286 //------------------------------------------------------------------------------
1287 template <typename U, typename T>
1288 template <typename OU, typename OT>
1290  (Quantity<OU, OT> const other) const
1291  -> quantity_t
1292 {
1293  static_assert(std::is_same<Quantity<OU, OT>, quantity_t>(),
1294  "Only quantities with exactly the same unit can be added."
1295  );
1296  return quantity_t(value() + other.value());
1297 } // util::quantities::concepts::Quantity<>::operator+
1298 
1299 
1300 //------------------------------------------------------------------------------
1301 template <typename U, typename T>
1302 template <typename OU, typename OT>
1304  (Quantity<OU, OT> const other) const
1305  -> quantity_t
1306 {
1307  static_assert(std::is_same<Quantity<OU, OT>, quantity_t>(),
1308  "Only quantities with exactly the same unit can be subtracted."
1309  );
1310  return quantity_t(value() - other.value());
1311 } // util::quantities::concepts::Quantity<>::operator+
1312 
1313 
1314 //------------------------------------------------------------------------------
1315 template <typename U, typename T>
1316 template <typename OU, typename OT>
1318  (Quantity<OU, OT> const other) const
1319  -> quantity_t
1320 {
1321  static_assert
1322  (sameBaseUnitAs<OU>(), "Can't add quantities with different base unit");
1323 
1324  // if the two quantities have the same *scaled* unit, add
1325  if constexpr (sameUnitAs<OU>()) {
1326  return quantity_t(fValue + other.value());
1327  return *this;
1328  }
1329  else {
1330  // otherwise, they have same base unit but different scale: convert `other`
1331  return (*this + quantity_t(other));
1332  }
1333 } // util::quantities::concepts::Quantity<>::operator+()
1334 
1335 
1336 //------------------------------------------------------------------------------
1337 template <typename U, typename T>
1338 template <typename OU, typename OT>
1340  (Quantity<OU, OT> const other) const
1341  -> quantity_t
1342 {
1343  static_assert
1344  (sameBaseUnitAs<OU>(), "Can't subtract quantities with different base unit");
1345 
1346  // if the two quantities have the same *scaled* unit, add
1347  if constexpr (sameUnitAs<OU>()) {
1348  return quantity_t(fValue - other.value());
1349  return *this;
1350  }
1351  else {
1352  // otherwise, they have same base unit but different scale: convert `other`
1353  return (*this - quantity_t(other));
1354  }
1355 } // util::quantities::concepts::Quantity<>::minus()
1356 
1357 
1358 //------------------------------------------------------------------------------
1359 template <typename U, typename T>
1360 template <typename OU, typename OT>
1362  (Quantity<OU, OT> const q) const
1363  -> value_t
1364 {
1365  static_assert
1366  (sameBaseUnitAs<OU>(), "Can't divide quantities with different base unit");
1367 
1368  // if the two quantities have the same *scaled* unit, divide
1369  if constexpr (sameUnitAs<OU>()) {
1370  return value() / q.value();
1371  }
1372  else {
1373  // otherwise, they have same base unit but different scale: convert `other`
1374  return (*this) / quantity_t(q);
1375  }
1376 } // util::quantities::concepts::Quantity<>::operator/(Quantity)
1377 
1378 
1379 //------------------------------------------------------------------------------
1380 template <typename U, typename T>
1381 template <typename OU, typename OT>
1384  -> quantity_t&
1385 {
1386  static_assert
1387  (sameBaseUnitAs<OU>(), "Can't add quantities with different base unit");
1388 
1389  // if the two quantities have the same *scaled* unit, add
1390  if constexpr (sameUnitAs<OU>()) {
1391  fValue += other.value();
1392  return *this;
1393  }
1394  else {
1395  // otherwise, they have same base unit but different scale: convert `other`
1396  return (*this += quantity_t(other));
1397  }
1398 } // util::quantities::concepts::Quantity<>::operator+=()
1399 
1400 
1401 //------------------------------------------------------------------------------
1402 template <typename U, typename T>
1403 template <typename OU, typename OT>
1406  -> quantity_t&
1407 {
1408  static_assert(sameBaseUnitAs<OU>(),
1409  "Can't subtract quantities with different base unit"
1410  );
1411 
1412  // if the two quantities have the same *scaled* unit, add
1413  if constexpr (sameUnitAs<OU>()) {
1414  fValue -= other.value();
1415  return *this;
1416  }
1417  else {
1418  // otherwise, they have same base unit but different scale: convert `other`
1419  return (*this -= quantity_t(other));
1420  }
1421 } // util::quantities::concepts::Quantity<>::operator-=()
1422 
1423 
1424 //------------------------------------------------------------------------------
1425 template <typename U, typename T>
1426 template <typename OU, typename OT>
1428  (Quantity<OU, OT> const other) const
1429 {
1430  static_assert
1431  (sameBaseUnitAs<OU>(), "Can't compare quantities with different base unit");
1432 
1433  // if the two quantities have the same *scaled* unit, just compare the values
1434  if constexpr (sameUnitAs<OU>()) {
1435  return value() == other.value();
1436  }
1437  else {
1438  // otherwise, they have same base unit but different scale: convert `other`
1439  return *this == quantity_t(other);
1440  }
1441 } // util::quantities::concepts::Quantity<>::operator==()
1442 
1443 
1444 //------------------------------------------------------------------------------
1445 template <typename U, typename T>
1446 template <typename OU, typename OT>
1447 constexpr bool util::quantities::concepts::Quantity<U, T>::operator!=
1448  (Quantity<OU, OT> const other) const
1449 {
1450  static_assert
1451  (sameBaseUnitAs<OU>(), "Can't compare quantities with different base unit");
1452 
1453  // if the two quantities have the same *scaled* unit, just compare the values
1454  if constexpr (sameUnitAs<OU>()) {
1455  return value() != other.value();
1456  }
1457  else {
1458  // otherwise, they have same base unit but different scale: convert `other`
1459  return *this != quantity_t(other);
1460  }
1461 } // util::quantities::concepts::Quantity<>::operator!=()
1462 
1463 
1464 //------------------------------------------------------------------------------
1465 template <typename U, typename T>
1466 template <typename OU, typename OT>
1467 constexpr bool util::quantities::concepts::Quantity<U, T>::operator<=
1468  (Quantity<OU, OT> const other) const
1469 {
1470  static_assert
1471  (sameBaseUnitAs<OU>(), "Can't compare quantities with different base unit");
1472 
1473  // if the two quantities have the same *scaled* unit, just compare the values
1474  if constexpr (sameUnitAs<OU>()) {
1475  return value() <= other.value();
1476  }
1477  else {
1478  // otherwise, they have same base unit but different scale: convert `other`
1479  return *this <= quantity_t(other);
1480  }
1481 } // util::quantities::concepts::Quantity<>::operator<=()
1482 
1483 
1484 //------------------------------------------------------------------------------
1485 template <typename U, typename T>
1486 template <typename OU, typename OT>
1487 constexpr bool util::quantities::concepts::Quantity<U, T>::operator>=
1488  (Quantity<OU, OT> const other) const
1489 {
1490  static_assert
1491  (sameBaseUnitAs<OU>(), "Can't compare quantities with different base unit");
1492 
1493  // if the two quantities have the same *scaled* unit, just compare the values
1494  if constexpr (sameUnitAs<OU>()) {
1495  return value() >= other.value();
1496  }
1497  else {
1498  // otherwise, they have same base unit but different scale: convert `other`
1499  return *this >= quantity_t(other);
1500  }
1501 } // util::quantities::concepts::Quantity<>::operator>=()
1502 
1503 
1504 //------------------------------------------------------------------------------
1505 template <typename U, typename T>
1506 template <typename OU, typename OT>
1507 constexpr bool util::quantities::concepts::Quantity<U, T>::operator<
1508  (Quantity<OU, OT> const other) const
1509 {
1510  static_assert
1511  (sameBaseUnitAs<OU>(), "Can't compare quantities with different base unit");
1512 
1513  // if the two quantities have the same *scaled* unit, just compare the values
1514  if constexpr (sameUnitAs<OU>()) {
1515  return value() < other.value();
1516  }
1517  else {
1518  // otherwise, they have same base unit but different scale: convert `other`
1519  return *this < quantity_t(other);
1520  }
1521 } // util::quantities::concepts::Quantity<>::operator<()
1522 
1523 
1524 //------------------------------------------------------------------------------
1525 template <typename U, typename T>
1526 template <typename OU, typename OT>
1527 constexpr bool util::quantities::concepts::Quantity<U, T>::operator>
1528  (Quantity<OU, OT> const other) const
1529 {
1530  static_assert
1531  (sameBaseUnitAs<OU>(), "Can't compare quantities with different base unit");
1532 
1533  // if the two quantities have the same *scaled* unit, just compare the values
1534  if constexpr (sameUnitAs<OU>()) {
1535  return value() > other.value();
1536  }
1537  else {
1538  // otherwise, they have same base unit but different scale: convert `other`
1539  return *this > quantity_t(other);
1540  }
1541 } // util::quantities::concepts::Quantity<>::operator>()
1542 
1543 
1544 //------------------------------------------------------------------------------
1546 
1547  /**
1548  * @brief Parses the unit of a string representing a `Quantity`.
1549  * @tparam Quantity the quantity being represented
1550  * @param str the string to be parsed
1551  * @param unitOptional (default: `false`) whether unit is not required
1552  * @return a pair: the unparsed part of `str` and the factor for parsed unit
1553  * @throw MissingUnit `s` does not contain the required unit
1554  * @throw ValueError the numerical value in `s` is not parseable
1555  * @throw ExtraCharactersError spurious characters after the numeric value
1556  * (including an unrecognised unit prefix)
1557  */
1558  template <typename Quantity>
1559  std::pair<std::string, typename Quantity::value_t> readUnit
1560  (std::string const& str, bool unitOptional = false);
1561 
1562 } // util::quantities::details
1563 
1564 
1565 //------------------------------------------------------------------------------
1566 template <typename Quantity>
1567 std::pair<std::string, typename Quantity::value_t>
1569  (std::string const& str, bool unitOptional /* = false */)
1570 {
1571  using Quantity_t = Quantity;
1572  using value_t = typename Quantity_t::value_t;
1573  using unit_t = typename Quantity_t::unit_t;
1574  using baseunit_t = typename unit_t::baseunit_t;
1575 
1576  // --- BEGIN -- static initialization ----------------------------------------
1577  using namespace std::string_literals;
1578 
1579  using PrefixMap_t = std::map<std::string, value_t>;
1580  using PrefixValue_t = typename PrefixMap_t::value_type;
1581  static PrefixMap_t const factors {
1582  PrefixValue_t{ "a"s, 1e-18 },
1583  PrefixValue_t{ "f"s, 1e-15 },
1584  PrefixValue_t{ "p"s, 1e-12 },
1585  PrefixValue_t{ "n"s, 1e-09 },
1586  PrefixValue_t{ "u"s, 1e-06 },
1587  PrefixValue_t{ "m"s, 1e-03 },
1588  PrefixValue_t{ "c"s, 1e-02 },
1589  PrefixValue_t{ "d"s, 1e-01 },
1590  PrefixValue_t{ ""s, 1e+00 },
1591  PrefixValue_t{ "da"s, 1e+01 },
1592  PrefixValue_t{ "h"s, 1e+02 },
1593  PrefixValue_t{ "k"s, 1e+03 },
1594  PrefixValue_t{ "M"s, 1e+06 },
1595  PrefixValue_t{ "G"s, 1e+09 },
1596  PrefixValue_t{ "T"s, 1e+12 },
1597  PrefixValue_t{ "P"s, 1e+15 },
1598  PrefixValue_t{ "E"s, 1e+18 }
1599  }; // factors
1600  static auto const composePrefixPattern = [](auto b, auto e) -> std::string
1601  {
1602  std::string pattern = "(";
1603  if (b != e) {
1604  pattern += b->first;
1605  while (++b != e) { pattern += '|'; pattern += b->first; }
1606  }
1607  return pattern += ")";
1608  };
1609  static std::string const prefixPattern
1610  = composePrefixPattern(factors.begin(), factors.end());
1611  // --- END -- static initialization ------------------------------------------
1612 
1613  std::regex const unitPattern {
1614  "[[:blank:]]*(" + prefixPattern + "?"
1615  + util::to_string(baseunit_t::symbol) + ")[[:blank:]]*$"
1616  };
1617 
1618  std::smatch unitMatch;
1619  if (!std::regex_search(str, unitMatch, unitPattern)) {
1620  if (!unitOptional) {
1621  throw MissingUnit("Unit is mandatory and must derive from '"
1622  + util::to_string(baseunit_t::symbol) + "' (parsing: '" + str + "')"
1623  );
1624  }
1625  return { str, value_t{ 1 } };
1626  }
1627 
1628  //
1629  // we do have a unit:
1630  //
1631 
1632  // " 7 cm " => [0] full match (" cm ") [1] unit ("cm") [2] unit prefix ("c")
1633  auto const iFactor = factors.find(unitMatch.str(2U));
1634  if (iFactor == factors.end()) {
1635  throw InvalidUnitPrefix(
1636  "Unit '" + unitMatch.str(1U)
1637  + "' has unsupported prefix '" + unitMatch.str(2U)
1638  + "' (parsing '" + str + "')"
1639  );
1640  }
1641 
1642  return {
1643  str.substr(0U, str.length() - unitMatch.length()),
1644  static_cast<value_t>(unit_t::scale(iFactor->second))
1645  };
1646 
1647 } // util::quantities::details::readUnit()
1648 
1649 
1650 //------------------------------------------------------------------------------
1651 template <typename Quantity>
1653  (std::string const& s, bool unitOptional /* = false */)
1654 {
1655  //
1656  // all this function is horrible;
1657  // some redesign is needed...
1658  //
1659  using value_t = typename Quantity::value_t;
1660 
1661  auto const [ num_s, factor ] = details::readUnit<Quantity>(s, unitOptional);
1662 
1663  char* parseEnd = nullptr;
1664  auto const value
1665  = static_cast<value_t>(std::strtod(num_s.c_str(), &parseEnd));
1666  const char* send = num_s.c_str() + num_s.length();
1667  if (parseEnd == num_s.c_str()) {
1668  throw ValueError("Could not convert '" + num_s + "' into a number!");
1669  }
1670  while (parseEnd != send) {
1671  if (!std::isblank(static_cast<unsigned char>(*parseEnd))) {
1672  throw ExtraCharactersError("Spurious characters after value "
1673  + std::to_string(value) + " in '" + num_s + "' ('"
1674  + std::string(parseEnd, send - parseEnd) + "')\n"
1675  );
1676  }
1677  ++parseEnd;
1678  } // while
1679 
1680  //
1681  // create and return the quantity
1682  //
1683  return Quantity{ static_cast<value_t>(value * factor) };
1684 } // util::quantities::makeQuantity(string_view)
1685 
1686 
1687 //------------------------------------------------------------------------------
1688 template <typename Quantity>
1690  (std::string_view s, bool unitOptional /* = false */)
1691 {
1692  return util::quantities::makeQuantity<Quantity>
1693  (std::string{ s.begin(), s.end() }, unitOptional);
1694 } // util::quantities::makeQuantity(string_view)
1695 
1696 
1697 //------------------------------------------------------------------------------
1698 template <typename Quantity>
1700  (char const* s, bool unitOptional /* = false */)
1701 {
1702  return
1703  util::quantities::makeQuantity<Quantity>(std::string_view{s}, unitOptional);
1704 } // util::quantities::makeQuantity(string)
1705 
1706 
1707 //------------------------------------------------------------------------------
1708 //--- Standard library extensions
1709 //------------------------------------------------------------------------------
1710 namespace std {
1711 
1712  // ---------------------------------------------------------------------------
1713  /// Hash function of a quantity is delegated to its value
1714  template <typename... Args>
1715  struct hash<util::quantities::concepts::Quantity<Args...>> {
1716  private:
1718  using value_t = typename quantity_t::value_t;
1719 
1720  public:
1721  constexpr auto operator()(quantity_t key) const
1722  noexcept(noexcept(std::hash<value_t>()(key.value())))
1723  { return std::hash<value_t>()(key.value()); }
1724  };
1725 
1726 
1727  // ---------------------------------------------------------------------------
1728  /// Limits of a quantity are the same as the underlying type.
1729  template <typename Unit, typename T>
1730  class numeric_limits<util::quantities::concepts::Quantity<Unit, T>>
1732  <util::quantities::concepts::Quantity<Unit, T>>
1733  {};
1734 
1735  template <typename Unit, typename T>
1736  class numeric_limits
1737  <util::quantities::concepts::Quantity<Unit, T> const>
1739  <util::quantities::concepts::Quantity<Unit, T> const>
1740  {};
1741 
1742  template <typename Unit, typename T>
1743  class numeric_limits
1744  <util::quantities::concepts::Quantity<Unit, T> volatile>
1746  <util::quantities::concepts::Quantity<Unit, T> volatile>
1747  {};
1748 
1749  template <typename Unit, typename T>
1750  class numeric_limits
1751  <util::quantities::concepts::Quantity<Unit, T> const volatile>
1753  <util::quantities::concepts::Quantity<Unit, T> const volatile>
1754  {};
1755 
1756 
1757  // ---------------------------------------------------------------------------
1758 
1759 } // namespace std
1760 
1761 
1762 //------------------------------------------------------------------------------
1763 
1764 #endif // LARDATAALG_UTILITIES_QUANTITIES_H
static QCString name
Definition: declinfo.cpp:673
constexpr quantity_t plus(Quantity< OU, OT > const other) const
Returns a quantity sum of this and other.
std::enable_if_t< std::is_arithmetic_v< OT >, quantity_t & > operator*=(OT factor)
Scale this quantity by a factor.
Definition: quantities.h:679
Namespace for general, non-LArSoft-specific utilities.
constexpr std::enable_if_t< std::is_arithmetic_v< T >, Interval< Q, Cat > > operator/(Interval< Q, Cat > const iv, T const quot)
Definition: intervals.h:521
static constexpr T unscale(T v)
Converts a value from this scaled unit to the base one.
Definition: quantities.h:436
constexpr bool is_value_compatible_with_v
Trait: true if the type T is compatible with the value of Q.
Definition: quantities.h:301
static constexpr T scaleTo(T v)
Converts a value from the scaled unit to a different TargetRatio.
Definition: quantities.h:441
Basic C++ metaprogramming utilities.
static constexpr baseunit_t baseUnit()
Returns an object with as type the base unit (baseunit_t).
Definition: quantities.h:748
Trait: true_type if U is a ScaledUnit-based object.
Definition: quantities.h:256
constexpr bool operator>(Interval< Q, Cat > const a, Quantity< Args... > const b) noexcept
Definition: intervals.h:476
DoubleProduct & operator+=(DoubleProduct &left, DoubleProduct const &right)
Definition: ToyProducts.h:103
static constexpr auto applyRatioToValue(Value &&v)
Applies the specified Ratio to the value in v.
Definition: quantities.h:236
std::string string
Definition: nybbler.cc:12
static constexpr quantity_t lowest() noexcept
Definition: quantities.h:1222
static constexpr T scale(T v)
Converts a value from the base unit to this one.
Definition: quantities.h:431
constexpr Point< Q, Cat, IV > operator+(Interval< OQ, OC > const delta, Point< Q, Cat, IV > const p)=delete
static constexpr bool sameUnitAs()
Returns whether scaled unit U has the same base unit as this one.
Definition: quantities.h:478
constexpr auto abs(T v)
Returns the absolute value of the argument.
Unit unit_t
The unit and scale of this quantity.
Definition: quantities.h:571
STL namespace.
static constexpr quantity_t castFrom(U value)
Returns a new quantity initialized with the specified value.
Definition: quantities.h:825
static constexpr T fromRepr(T v)
Converts a value from TargetRatio scale to this scaled unit.
Definition: quantities.h:449
static constexpr quantity_t signaling_NaN() noexcept
Definition: quantities.h:1232
constexpr value_t value() const
Returns the value of the quantity.
Definition: quantities.h:609
int find(char c, int index=0, bool cs=TRUE) const
Definition: qcstring.cpp:41
static constexpr bool sameBaseUnitAs()
Returns whether scaled unit U has the same base unit as this one.
Definition: quantities.h:473
static auto symbol()
Returns short symbol of the unit (e.g. "ns") is a string-like object.
Definition: quantities.h:413
std::integral_constant< bool, Value > bool_constant
Definition: ProviderPack.h:314
std::string to_string(Interval< Q, Cat > const &iv)
Definition: intervals.h:537
constexpr Quantity(value_t v)
Constructor: takes a value in the intended representation.
Definition: quantities.h:584
std::numeric_limits< typename quantity_t::value_t > value_traits_t
Definition: quantities.h:1214
constexpr bool is_quantity_v
Trait: true if Q is a Quantity specialization.
Definition: quantities.h:268
static constexpr bool isCompatibleValue()
Returns whether U is a value type compatible with value_t.
Definition: quantities.h:786
static auto unitSymbol()
Returns the symbol of the unit, in a string-like object.
Definition: quantities.h:754
std::enable_if_t< std::is_arithmetic_v< OT >, quantity_t & > operator/=(OT quot)
Scale the quantity dividing it by a quotient.
Definition: quantities.h:684
static constexpr baseunit_t baseUnit()
Returns an instance of the baseunit_t type.
Definition: quantities.h:466
static constexpr prefix_t prefix()
Returns an instance of the prefix_t type.
Definition: quantities.h:463
static constexpr quantity_t min() noexcept
Definition: quantities.h:1218
Trait: true_type if Q is a Quantity-based object.
Definition: quantities.h:272
String representing a quantity has spurious characters after the number.
Definition: quantities.h:1108
R ratio
The ratio to go from the base unit to this one.
Definition: quantities.h:398
const double e
constexpr OQ convertInto() const
Convert this quantity into the specified one.
Definition: quantities.h:801
constexpr bool has_value_compatible_with_v
Trait: true if the value type of T is compatible with U&#39;s.
Definition: quantities.h:318
def key(type, name=None)
Definition: graph.py:13
decltype(auto) constexpr to_string(T &&obj)
ADL-aware version of std::to_string.
constexpr bool operator>=(Interval< Q, Cat > const a, Quantity< Args... > const b) noexcept
Definition: intervals.h:466
typename unit_t::baseunit_t baseunit_t
Description of the unscaled unit.
Definition: quantities.h:575
constexpr quantity_t minus(Quantity< OU, OT > const other) const
Returns a quantity difference of this and other.
U baseunit_t
Base, unscaled unit.
Definition: quantities.h:396
A value measured in the specified unit.
Definition: quantities.h:566
static constexpr quantity_t quiet_NaN() noexcept
Definition: quantities.h:1230
static constexpr unit_t unit()
Returns an object with as type the scaled unit (unit_t).
Definition: quantities.h:745
constexpr auto operator()(quantity_t key) const noexcept(noexcept(std::hash< value_t >()(key.value())))
Definition: quantities.h:1721
std::string to_string(Quantity< Args... > const &q)
Definition: quantities.h:949
constexpr bool operator==(Interval< Q, Cat > const a, Quantity< Args... > const b) noexcept
Definition: intervals.h:426
constexpr quantity_t operator-() const
Returns a quantity with same value but the sign flipped.
Definition: quantities.h:690
details::simplify_ratio< std::ratio_divide< NumRatio, DenRatio >> simplified_ratio_divide
A ratio division (like std::ratio_divide) with simplified terms.
Definition: quantities.h:348
static constexpr unit_t unit()
Returns an instance of the unit_t type.
Definition: quantities.h:469
static int max(int a, int b)
static constexpr quantity_t epsilon() noexcept
Definition: quantities.h:1224
constexpr bool operator!=(Interval< Q, Cat > const a, Quantity< Args... > const b) noexcept
Definition: intervals.h:436
constexpr bool has_unit_v
Trait: true if U is a ScaledUnit-based object.
Definition: quantities.h:260
static constexpr quantity_t round_error() noexcept
Definition: quantities.h:1226
constexpr bool has_quantity_v
Trait: true if Q is a Quantity-based object.
Definition: quantities.h:276
T value_t
Type of the stored value.
Definition: quantities.h:570
Mathematical functions that C++ standard doesn&#39;t require constexpr.
typename quantity_value_type< T >::type quantity_value_t
Definition: quantities.h:288
String representing a quantity has unsupported unit prefix.
Definition: quantities.h:1096
static constexpr auto symbol()
Returns the symbol of the prefix.
Definition: quantities.h:385
static constexpr quantity_t max() noexcept
Definition: quantities.h:1220
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
String representing a quantity has incompatible unit.
Definition: quantities.h:1100
std::ostream & operator<<(std::ostream &out, Interval< Args... > const iv)
Definition: intervals.h:407
String representing a quantity has no unit.
Definition: quantities.h:1092
constexpr Point< Q, Cat, IV > operator-(Interval< OQ, OC > const delta, Point< Q, Cat, IV > const p)=delete
static constexpr bool sameUnitAs()
Returns whether this quantity has same unit and scale as OU.
Definition: quantities.h:771
std::string pattern
Definition: regex_t.cc:35
Functions pulling in STL customization if available.
Quantity makeQuantity(std::string_view s, bool unitOptional=false)
Returns a quantity of the specified type parsed from a string.
Definition: quantities.h:1690
details::simplify_ratio< std::ratio_multiply< ARatio, BRatio >> simplified_ratio_multiply
A ratio product (like std::ratio_multiply) with simplified terms.
Definition: quantities.h:343
typename invert_ratio< R >::type invert_t
Definition: quantities.h:243
constexpr std::enable_if_t< std::is_arithmetic_v< T >, Interval< Q, Cat > > operator*(Interval< Q, Cat > const iv, T const factor)
Multiplication with a scalar.
Definition: intervals.h:505
static bool * b
Definition: config.cpp:1043
Limits of a quantity are the same as the underlying type.
Definition: quantities.h:329
static constexpr auto name()
Returns the full name of the prefix.
Definition: quantities.h:388
typename ratio_simplifier< R >::type simplify_ratio
Definition: quantities.h:249
R ratio
The ratio this prefix is about.
Definition: quantities.h:379
static auto unitName()
Returns the full name of the unit, in a string-like object.
Definition: quantities.h:751
Types of variables with a unit.
Definition: intervals.h:20
static std::vector< std::string > const names
Definition: FragmentType.hh:8
static constexpr bool sameBaseUnitAs()
Returns whether this quantity has the same base unit as OU.
Definition: quantities.h:762
constexpr quantity_t abs() const
Returns a quantity with the absolute value of this one.
Definition: quantities.h:693
String representing a quantity has an invalid number.
Definition: quantities.h:1104
static constexpr bool hasCompatibleValue()
Definition: quantities.h:792
constexpr quantity_t operator+() const
Returns a quantity with same value.
Definition: quantities.h:687
static QCString * s
Definition: config.cpp:1042
static QCString str
constexpr Quantity(Q q)
Constructor: converts from another quantity.
Definition: quantities.h:599
static constexpr auto names(bool Long=false)
Returns the unit symbol (Long false) or name (Long true).
Definition: quantities.h:1251
Trait: true_type if Q is a Quantity specialization.
Definition: quantities.h:264
static constexpr quantity_t denorm_min() noexcept
Definition: quantities.h:1234
std::pair< std::string, typename Quantity::value_t > readUnit(std::string const &str, bool unitOptional=false)
Parses the unit of a string representing a Quantity.
Definition: quantities.h:1569
static constexpr quantity_t infinity() noexcept
Definition: quantities.h:1228