29 #ifndef LARDATAALG_UTILITIES_QUANTITIES_H 30 #define LARDATAALG_UTILITIES_QUANTITIES_H 38 #include "boost/integer/common_factor_rt.hpp" 49 #include <string_view> 50 #include <type_traits> 234 template <
typename Ratio,
typename Value>
240 template <
typename R>
243 template <
typename R>
246 template <
typename R>
249 template <
typename R>
256 template <
typename U>
260 template <
typename U>
264 template <
typename Q>
268 template <
typename Q>
272 template <
typename Q>
276 template <
typename Q>
282 template <
typename T>
287 template <
typename T>
294 template <
typename T,
typename Q>
298 template <
typename T,
typename Q>
309 template <
typename T,
typename U>
313 template <
typename T,
typename U>
323 template <
typename Q>
334 template <
typename ARatio,
typename BRatio>
338 template <
typename NumRatio,
typename DenRatio>
361 static constexpr std::string_view symbol =
"?"sv;
363 static constexpr std::string_view name =
"unknown"sv;
366 template <
typename R>
371 static constexpr
auto names(
bool Long =
false);
374 static constexpr
auto symbol() {
return names(
false); }
377 static constexpr
auto name() {
return names(
true); }
381 template <
typename U,
typename R = std::ratio<1>>
400 static auto symbol() {
return std::string(prefix().
symbol()) + baseUnit().symbol.data(); }
404 static auto name() {
return std::string(prefix().
name()) + baseUnit().name.data(); }
414 template <
typename T>
417 return details::applyRatioToValue<details::invert_t<ratio>>(v);
421 template <
typename T>
424 return details::applyRatioToValue<ratio>(v);
428 template <
typename TargetRatio,
typename T>
431 return details::applyRatioToValue<simplified_ratio_divide<ratio, TargetRatio>>(v);
435 template <
typename TargetRatio,
typename T>
438 return details::applyRatioToValue<simplified_ratio_divide<TargetRatio, ratio>>(v);
458 template <
typename OU>
461 return std::is_same<baseunit_t, typename OU::baseunit_t>();
465 template <
typename OU>
468 return std::is_same<unit_t, typename OU::unit_t>();
476 template <
typename U,
typename R>
477 std::ostream& operator<<(std::ostream& out, ScaledUnit<U, R>
const& unit)
480 return out << unit_t::prefix_t::symbol() << unit_t::baseunit_t::symbol;
553 template <
typename Unit,
typename T =
double>
581 template <
typename Q,
typename std::enable_if_t<details::is_quantity_v<Q>>* =
nullptr>
583 : fValue{unit_t::template fromRepr<typename Q::unit_t::ratio>(q.value())}
585 static_assert(sameBaseUnitAs<Q>(),
586 "Can't construct from quantity with different base unit");
628 template <
typename OU,
typename OT>
633 template <
typename OU,
typename OT>
637 template <
typename OU,
typename OT>
641 template <
typename OU,
typename OT>
645 template <
typename OU,
typename OT>
649 template <
typename OU,
typename OT>
653 template <
typename OU,
typename OT>
657 template <
typename OT>
665 template <
typename OT>
702 template <
typename OU,
typename OT>
705 template <
typename OU,
typename OT>
708 template <
typename OU,
typename OT>
711 template <
typename OU,
typename OT>
714 template <
typename OU,
typename OT>
715 constexpr
bool operator<=(Quantity<OU, OT>
const other)
const;
717 template <
typename OU,
typename OT>
718 constexpr
bool operator<(Quantity<OU, OT>
const other)
const;
744 template <
typename OU>
747 return unit_t::template sameBaseUnitAs<OU>();
755 template <
typename OU>
758 return unit_t::template sameUnitAs<OU>();
762 template <
typename U>
763 static constexpr
bool is_compatible_value_v = details::is_value_compatible_with_v<U, value_t>;
766 template <
typename U>
767 static constexpr
bool has_compatible_value_v =
768 details::has_value_compatible_with_v<U, value_t>;
771 template <
typename U>
774 return quantity_t::is_compatible_value_v<U>;
779 template <
typename U>
782 return quantity_t::has_compatible_value_v<U>;
789 template <
typename OQ>
815 template <
typename U>
826 template <
typename... Args>
829 return out << q.
value() <<
" " << q.
unit();
854 template <
typename U,
typename T>
856 template <
typename U,
typename T>
858 template <
typename U,
typename T>
860 template <
typename U,
typename T>
865 template <
typename U,
typename T,
typename OT>
867 constexpr std::enable_if_t<Quantity<U, T>::template is_compatible_value_v<OT>,
Quantity<U, T>>
872 template <
typename U,
typename T,
typename OT>
873 constexpr std::enable_if_t<Quantity<U, T>::template is_compatible_value_v<OT>,
Quantity<U, T>>
881 template <
typename AU,
typename AT,
typename BU,
typename BT>
884 -> decltype(std::declval<AT>() * std::declval<BT>()) =
delete;
889 template <
typename U,
typename T,
typename OT>
890 constexpr std::enable_if_t<Quantity<U, T>::template is_compatible_value_v<OT>,
Quantity<U, T>>
907 template <
typename Unit,
typename Ratio,
typename T>
912 template <
typename Q,
typename R,
typename T =
typename Q::value_t>
924 template <
typename... Args>
927 return std::string(unit.
prefix().symbol()) + unit.
baseUnit().symbol.data();
932 template <
typename... Args>
994 using std::atto, std::femto, std::pico, std::nano, std::micro, std::milli, std::centi,
995 std::deci, std::deca, std::hecto, std::kilo, std::mega, std::giga, std::tera, std::peta,
1058 template <
typename Quantity>
1061 template <
typename Quantity>
1064 template <
typename Quantity>
1073 using std::runtime_error::runtime_error;
1078 using std::runtime_error::runtime_error;
1083 using std::runtime_error::runtime_error;
1088 using std::runtime_error::runtime_error;
1093 using std::runtime_error::runtime_error;
1108 template <std::
intmax_t Num, std::
intmax_t Den>
1114 template <std::
intmax_t Num, std::
intmax_t Den>
1116 static constexpr
auto gcd = boost::integer::gcd(Num, Den);
1117 using type = std::ratio<Num / gcd, Den / gcd>;
1121 template <
typename U,
typename Enable =
void>
1124 template <
typename U>
1126 :
public std::true_type {};
1128 template <
typename U>
1132 template <
typename Q>
1135 template <
typename... Args>
1139 template <
typename Q,
typename Enable =
void>
1142 template <
typename Q>
1144 :
public std::true_type {};
1146 template <
typename Q>
1150 template <
typename T,
typename =
void>
1155 template <
typename T>
1158 std::enable_if_t<(has_unit_v<T> && util::always_true_v<typename T::value_t>)>> {
1162 template <
typename T>
1166 template <
typename T,
typename Q>
1171 template <
typename T,
typename U>
1176 template <
typename Q>
1177 class numeric_limits :
public std::numeric_limits<typename Q::value_t> {
1189 return quantity_t{value_traits_t::round_error()};
1193 return quantity_t{value_traits_t::infinity()};
1197 return quantity_t{value_traits_t::quiet_NaN()};
1201 return quantity_t{value_traits_t::signaling_NaN()};
1205 return quantity_t{value_traits_t::denorm_min()};
1219 template <
typename R>
1222 if constexpr (std::is_same<ratio, std::tera>())
return Long ?
"tera"sv :
"T"sv;
1223 if constexpr (std::is_same<ratio, std::giga>())
return Long ?
"giga"sv :
"G"sv;
1224 if constexpr (std::is_same<ratio, std::mega>())
return Long ?
"mega"sv :
"M"sv;
1225 if constexpr (std::is_same<ratio, std::kilo>())
return Long ?
"kilo"sv :
"k"sv;
1226 if constexpr (std::is_same<
ratio, std::ratio<1>>())
return ""sv;
1227 if constexpr (std::is_same<ratio, std::deci>())
return Long ?
"deci"sv :
"d"sv;
1228 if constexpr (std::is_same<ratio, std::centi>())
return Long ?
"centi"sv :
"c"sv;
1229 if constexpr (std::is_same<ratio, std::milli>())
return Long ?
"milli"sv :
"m"sv;
1230 if constexpr (std::is_same<ratio, std::micro>())
return Long ?
"micro"sv :
"u"sv;
1231 if constexpr (std::is_same<ratio, std::nano>())
return Long ?
"nano"sv :
"n"sv;
1232 if constexpr (std::is_same<ratio, std::pico>())
return Long ?
"pico"sv :
"p"sv;
1233 if constexpr (std::is_same<ratio, std::femto>())
return Long ?
"femto"sv :
"f"sv;
1237 return Long ?
"???"sv :
"?"sv;
1243 template <
typename U,
typename T>
1244 template <
typename OU,
typename OT>
1249 "Only quantities with exactly the same unit can be added.");
1254 template <
typename U,
typename T>
1255 template <
typename OU,
typename OT>
1260 "Only quantities with exactly the same unit can be subtracted.");
1265 template <
typename U,
typename T>
1266 template <
typename OU,
typename OT>
1270 static_assert(sameBaseUnitAs<OU>(),
"Can't add quantities with different base unit");
1273 if constexpr (sameUnitAs<OU>()) {
1284 template <
typename U,
typename T>
1285 template <
typename OU,
typename OT>
1289 static_assert(sameBaseUnitAs<OU>(),
"Can't subtract quantities with different base unit");
1292 if constexpr (sameUnitAs<OU>()) {
1303 template <
typename U,
typename T>
1304 template <
typename OU,
typename OT>
1308 static_assert(sameBaseUnitAs<OU>(),
"Can't divide quantities with different base unit");
1311 if constexpr (sameUnitAs<OU>()) {
return value() / q.value(); }
1319 template <
typename U,
typename T>
1320 template <
typename OU,
typename OT>
1324 static_assert(sameBaseUnitAs<OU>(),
"Can't add quantities with different base unit");
1327 if constexpr (sameUnitAs<OU>()) {
1328 fValue +=
other.value();
1338 template <
typename U,
typename T>
1339 template <
typename OU,
typename OT>
1343 static_assert(sameBaseUnitAs<OU>(),
"Can't subtract quantities with different base unit");
1346 if constexpr (sameUnitAs<OU>()) {
1347 fValue -=
other.value();
1357 template <
typename U,
typename T>
1358 template <
typename OU,
typename OT>
1362 static_assert(sameBaseUnitAs<OU>(),
"Can't compare quantities with different base unit");
1365 if constexpr (sameUnitAs<OU>()) {
return value() == other.
value(); }
1373 template <
typename U,
typename T>
1374 template <
typename OU,
typename OT>
1378 static_assert(sameBaseUnitAs<OU>(),
"Can't compare quantities with different base unit");
1381 if constexpr (sameUnitAs<OU>()) {
return value() != other.
value(); }
1389 template <
typename U,
typename T>
1390 template <
typename OU,
typename OT>
1394 static_assert(sameBaseUnitAs<OU>(),
"Can't compare quantities with different base unit");
1397 if constexpr (sameUnitAs<OU>()) {
return value() <= other.
value(); }
1405 template <
typename U,
typename T>
1406 template <
typename OU,
typename OT>
1410 static_assert(sameBaseUnitAs<OU>(),
"Can't compare quantities with different base unit");
1413 if constexpr (sameUnitAs<OU>()) {
return value() >= other.
value(); }
1421 template <
typename U,
typename T>
1422 template <
typename OU,
typename OT>
1426 static_assert(sameBaseUnitAs<OU>(),
"Can't compare quantities with different base unit");
1429 if constexpr (sameUnitAs<OU>()) {
return value() < other.
value(); }
1437 template <
typename U,
typename T>
1438 template <
typename OU,
typename OT>
1442 static_assert(sameBaseUnitAs<OU>(),
"Can't compare quantities with different base unit");
1445 if constexpr (sameUnitAs<OU>()) {
return value() > other.
value(); }
1466 template <
typename Quantity>
1467 std::pair<std::string, typename Quantity::value_t>
readUnit(std::string
const& str,
1468 bool unitOptional =
false);
1473 template <
typename Quantity>
1475 std::string
const& str,
1478 using Quantity_t = Quantity;
1479 using value_t =
typename Quantity_t::value_t;
1480 using unit_t =
typename Quantity_t::unit_t;
1481 using baseunit_t =
typename unit_t::baseunit_t;
1486 using PrefixMap_t = std::map<std::string, value_t>;
1487 using PrefixValue_t =
typename PrefixMap_t::value_type;
1488 static PrefixMap_t
const factors{PrefixValue_t{
"a"s, 1
e-18},
1489 PrefixValue_t{
"f"s, 1e-15},
1490 PrefixValue_t{
"p"s, 1e-12},
1491 PrefixValue_t{
"n"s, 1e-09},
1492 PrefixValue_t{
"u"s, 1e-06},
1493 PrefixValue_t{
"m"s, 1e-03},
1494 PrefixValue_t{
"c"s, 1e-02},
1495 PrefixValue_t{
"d"s, 1e-01},
1496 PrefixValue_t{
""s, 1e+00},
1497 PrefixValue_t{
"da"s, 1e+01},
1498 PrefixValue_t{
"h"s, 1e+02},
1499 PrefixValue_t{
"k"s, 1e+03},
1500 PrefixValue_t{
"M"s, 1e+06},
1501 PrefixValue_t{
"G"s, 1e+09},
1502 PrefixValue_t{
"T"s, 1e+12},
1503 PrefixValue_t{
"P"s, 1e+15},
1504 PrefixValue_t{
"E"s, 1e+18}};
1505 static auto const composePrefixPattern = [](
auto b,
auto e) -> std::string {
1506 std::string pattern =
"(";
1508 pattern += b->first;
1511 pattern += b->first;
1514 return pattern +=
")";
1516 static std::string
const prefixPattern = composePrefixPattern(factors.begin(), factors.end());
1519 std::regex
const unitPattern{
"[[:blank:]]*(" + prefixPattern +
"?" +
1522 std::smatch unitMatch;
1523 if (!std::regex_search(str, unitMatch, unitPattern)) {
1524 if (!unitOptional) {
1525 throw MissingUnit(
"Unit is mandatory and must derive from '" +
1528 return {str, value_t{1}};
1536 auto const iFactor = factors.find(unitMatch.str(2U));
1537 if (iFactor == factors.end()) {
1538 throw InvalidUnitPrefix(
"Unit '" + unitMatch.str(1U) +
"' has unsupported prefix '" +
1539 unitMatch.str(2U) +
"' (parsing '" + str +
"')");
1542 return {str.substr(0U, str.length() - unitMatch.length()),
1548 template <
typename Quantity>
1557 auto const [num_s, factor] = details::readUnit<Quantity>(s, unitOptional);
1559 char* parseEnd =
nullptr;
1560 auto const value =
static_cast<value_t
>(std::strtod(num_s.c_str(), &parseEnd));
1561 const char* send = num_s.c_str() + num_s.length();
1562 if (parseEnd == num_s.c_str()) {
1563 throw ValueError(
"Could not convert '" + num_s +
"' into a number!");
1565 while (parseEnd != send) {
1566 if (!std::isblank(static_cast<unsigned char>(*parseEnd))) {
1568 " in '" + num_s +
"' ('" + std::string(parseEnd, send - parseEnd) +
1577 return Quantity{
static_cast<value_t
>(
value * factor)};
1581 template <
typename Quantity>
1584 return util::quantities::makeQuantity<Quantity>(std::string{s.begin(), s.end()}, unitOptional);
1588 template <
typename Quantity>
1591 return util::quantities::makeQuantity<Quantity>(std::string_view{s}, unitOptional);
1601 template <
typename... Args>
1602 struct hash<
util::quantities::concepts::Quantity<Args...>> {
1609 noexcept(noexcept(std::hash<value_t>()(key.value())))
1611 return std::hash<value_t>()(key.value());
1617 template <
typename Unit,
typename T>
1618 class numeric_limits<
util::quantities::concepts::Quantity<Unit, T>>
1620 util::quantities::concepts::Quantity<Unit, T>> {};
1622 template <
typename Unit,
typename T>
1623 class numeric_limits<util::quantities::concepts::Quantity<Unit, T> const>
1625 util::quantities::concepts::Quantity<Unit, T> const> {};
1627 template <
typename Unit,
typename T>
1628 class numeric_limits<util::quantities::concepts::Quantity<Unit, T> volatile>
1630 util::quantities::concepts::Quantity<Unit, T> volatile> {};
1632 template <
typename Unit,
typename T>
1633 class numeric_limits<util::quantities::concepts::Quantity<Unit, T> const volatile>
1635 util::quantities::concepts::Quantity<Unit, T> const volatile> {};
1643 #endif // LARDATAALG_UTILITIES_QUANTITIES_H constexpr bool operator>=(Quantity< OU, OT > const other) const
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.
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)
static constexpr T unscale(T v)
Converts a value from this scaled unit to the base one.
constexpr bool is_value_compatible_with_v
Trait: true if the type T is compatible with the value of Q.
static constexpr T scaleTo(T v)
Converts a value from the scaled unit to a different TargetRatio.
static constexpr baseunit_t baseUnit()
Returns an object with as type the base unit (baseunit_t).
Trait: true_type if U is a ScaledUnit-based object.
constexpr bool operator>(Interval< Q, Cat > const a, Quantity< Args... > const b) noexcept
constexpr bool operator==(Quantity< OU, OT > const other) const
static constexpr auto applyRatioToValue(Value &&v)
Applies the specified Ratio to the value in v.
static constexpr quantity_t lowest() noexcept
static constexpr T scale(T v)
Converts a value from the base unit to this one.
constexpr Point< Q, Cat, IV > operator+(Interval< OQ, OC > const delta, Point< Q, Cat, IV > const p)=delete
Multiplication with a scalar.
static constexpr bool sameUnitAs()
Returns whether scaled unit U has the same base unit as this one.
constexpr auto abs(T v)
Returns the absolute value of the argument.
quantity_t & operator-=(Quantity< OU, OT > const other)
Subtract the other quantity (possibly concerted) to this one.
Unit unit_t
The unit and scale of this quantity.
static constexpr quantity_t castFrom(U value)
Returns a new quantity initialized with the specified value.
quantity_t & operator+=(Quantity< OU, OT > const other)
Add the other quantity (possibly concerted) to this one.
static constexpr T fromRepr(T v)
Converts a value from TargetRatio scale to this scaled unit.
static constexpr quantity_t signaling_NaN() noexcept
constexpr value_t value() const
Returns the value of the quantity.
static constexpr bool sameBaseUnitAs()
Returns whether scaled unit U has the same base unit as this one.
static auto symbol()
Returns short symbol of the unit (e.g. "ns") is a string-like object.
std::integral_constant< bool, Value > bool_constant
std::string to_string(Interval< Q, Cat > const &iv)
constexpr Quantity(value_t v)
Constructor: takes a value in the intended representation.
std::numeric_limits< typename quantity_t::value_t > value_traits_t
constexpr bool is_quantity_v
Trait: true if Q is a Quantity specialization.
static constexpr bool isCompatibleValue()
Returns whether U is a value type compatible with value_t.
static auto unitSymbol()
Returns the symbol of the unit, in a string-like object.
std::enable_if_t< std::is_arithmetic_v< OT >, quantity_t & > operator/=(OT quot)
Scale the quantity dividing it by a quotient.
static constexpr baseunit_t baseUnit()
Returns an instance of the baseunit_t type.
static constexpr prefix_t prefix()
Returns an instance of the prefix_t type.
static constexpr quantity_t min() noexcept
Trait: true_type if Q is a Quantity-based object.
R ratio
The ratio to go from the base unit to this one.
constexpr OQ convertInto() const
Convert this quantity into the specified one.
constexpr bool has_value_compatible_with_v
Trait: true if the value type of T is compatible with U's.
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
constexpr bool operator>(Quantity< OU, OT > const other) const
typename unit_t::baseunit_t baseunit_t
Description of the unscaled unit.
constexpr quantity_t minus(Quantity< OU, OT > const other) const
Returns a quantity difference of this and other.
U baseunit_t
Base, unscaled unit.
A value measured in the specified unit.
static constexpr quantity_t quiet_NaN() noexcept
static constexpr unit_t unit()
Returns an object with as type the scaled unit (unit_t).
constexpr auto operator()(quantity_t key) const noexcept(noexcept(std::hash< value_t >()(key.value())))
std::string to_string(Quantity< Args... > const &q)
constexpr bool operator==(Interval< Q, Cat > const a, Quantity< Args... > const b) noexcept
constexpr quantity_t operator-() const
Returns a quantity with same value but the sign flipped.
constexpr bool operator<=(Quantity< OU, OT > const other) const
details::simplify_ratio< std::ratio_divide< NumRatio, DenRatio >> simplified_ratio_divide
A ratio division (like std::ratio_divide) with simplified terms.
static constexpr unit_t unit()
Returns an instance of the unit_t type.
String & operator+=(String &s, VectorDumper< Vector > const &manip)
Appends a string rendering of a vector to the specified string.
static constexpr quantity_t epsilon() noexcept
constexpr bool operator!=(Interval< Q, Cat > const a, Quantity< Args... > const b) noexcept
constexpr bool has_unit_v
Trait: true if U is a ScaledUnit-based object.
static constexpr quantity_t round_error() noexcept
constexpr bool has_quantity_v
Trait: true if Q is a Quantity-based object.
typename quantity_t::value_t value_t
T value_t
Type of the stored value.
Mathematical functions that C++ standard doesn't require constexpr.
typename quantity_value_type< T >::type quantity_value_t
String representing a quantity has unsupported unit prefix.
static constexpr auto symbol()
Returns the symbol of the prefix.
static constexpr quantity_t max() noexcept
String representing a quantity has incompatible unit.
std::ostream & operator<<(std::ostream &out, Interval< Args... > const iv)
String representing a quantity has no unit.
constexpr Point< Q, Cat, IV > operator-(Interval< OQ, OC > const delta, Point< Q, Cat, IV > const p)=delete
Multiplication with a scalar.
static constexpr bool sameUnitAs()
Returns whether this quantity has same unit and scale as OU.
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.
details::simplify_ratio< std::ratio_multiply< ARatio, BRatio >> simplified_ratio_multiply
A ratio product (like std::ratio_multiply) with simplified terms.
typename invert_ratio< R >::type invert_t
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.
constexpr bool operator!=(Quantity< OU, OT > const other) const
Limits of a quantity are the same as the underlying type.
static constexpr auto name()
Returns the full name of the prefix.
typename ratio_simplifier< R >::type simplify_ratio
R ratio
The ratio this prefix is about.
static auto unitName()
Returns the full name of the unit, in a string-like object.
Types of variables with a unit.
static constexpr bool sameBaseUnitAs()
Returns whether this quantity has the same base unit as OU.
constexpr quantity_t abs() const
Returns a quantity with the absolute value of this one.
String representing a quantity has an invalid number.
static constexpr bool hasCompatibleValue()
constexpr quantity_t operator+() const
Returns a quantity with same value.
constexpr Quantity(Q q)
Constructor: converts from another quantity.
static constexpr auto names(bool Long=false)
Returns the unit symbol (Long false) or name (Long true).
Trait: true_type if Q is a Quantity specialization.
static constexpr quantity_t denorm_min() noexcept
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.
constexpr value_t operator/(Quantity< OU, OT > q) const
Division by a quantity, returns a pure number.
constexpr bool operator<(Quantity< OU, OT > const other) const
static constexpr quantity_t infinity() noexcept