29 #ifndef LARDATAALG_UTILITIES_QUANTITIES_H 30 #define LARDATAALG_UTILITIES_QUANTITIES_H 38 #include "boost/integer/common_factor_rt.hpp" 44 #include <string_view> 49 #include <type_traits> 235 template <
typename Ratio,
typename Value>
239 template <
typename R>
242 template <
typename R>
245 template <
typename R>
248 template <
typename R>
255 template <
typename U>
259 template <
typename U>
263 template <
typename Q>
267 template <
typename Q>
271 template <
typename Q>
275 template <
typename Q>
282 template <
typename T>
287 template <
typename T>
295 template <
typename T,
typename Q>
299 template <
typename T,
typename Q>
312 template <
typename T,
typename U>
316 template <
typename T,
typename U>
328 template <
typename Q>
341 template <
typename ARatio,
typename BRatio>
346 template <
typename NumRatio,
typename DenRatio>
371 static constexpr std::string_view symbol =
"?"sv;
373 static constexpr std::string_view
name =
"unknown"sv;
377 template <
typename R>
382 static constexpr
auto names(
bool Long =
false);
393 template <
typename U,
typename R = std::ratio<1>>
430 template <
typename T>
432 {
return details::applyRatioToValue<details::invert_t<ratio>>(v); }
435 template <
typename T>
437 {
return details::applyRatioToValue<ratio>(v); }
440 template <
typename TargetRatio,
typename T>
448 template <
typename TargetRatio,
typename T>
472 template <
typename OU>
474 {
return std::is_same<baseunit_t, typename OU::baseunit_t>(); }
477 template <
typename OU>
479 {
return std::is_same<unit_t, typename OU::unit_t>(); }
487 template <
typename U,
typename R>
488 std::ostream& operator<< (std::ostream& out, ScaledUnit<U, R>
const& unit)
491 return out << unit_t::prefix_t::symbol() << unit_t::baseunit_t::symbol;
565 template <
typename Unit,
typename T =
double>
597 typename std::enable_if_t<details::is_quantity_v<Q>>* =
nullptr 601 {unit_t::template fromRepr<typename Q::unit_t::ratio>(q.value()) }
603 static_assert(sameBaseUnitAs<Q>(),
604 "Can't construct from quantity with different base unit" 648 template <
typename OU,
typename OT>
653 template <
typename OU,
typename OT>
657 template <
typename OU,
typename OT>
661 template <
typename OU,
typename OT>
665 template <
typename OU,
typename OT>
669 template <
typename OU,
typename OT>
673 template <
typename OU,
typename OT>
677 template <
typename OT>
678 std::enable_if_t<std::is_arithmetic_v<OT>,
quantity_t&>
682 template <
typename OT>
683 std::enable_if_t<std::is_arithmetic_v<OT>,
quantity_t&>
718 template <
typename OU,
typename OT>
721 template <
typename OU,
typename OT>
724 template <
typename OU,
typename OT>
727 template <
typename OU,
typename OT>
730 template <
typename OU,
typename OT>
731 constexpr
bool operator<=(Quantity<OU, OT>
const other)
const;
733 template <
typename OU,
typename OT>
734 constexpr
bool operator<(Quantity<OU, OT>
const other)
const;
761 template <
typename OU>
763 {
return unit_t::template sameBaseUnitAs<OU>(); }
770 template <
typename OU>
772 {
return unit_t::template sameUnitAs<OU>(); }
775 template <
typename U>
776 static constexpr
bool is_compatible_value_v
777 = details::is_value_compatible_with_v<U, value_t>;
780 template <
typename U>
781 static constexpr
bool has_compatible_value_v
782 = details::has_value_compatible_with_v<U, value_t>;
785 template <
typename U>
787 {
return quantity_t::is_compatible_value_v<U>; }
791 template <
typename U>
793 {
return quantity_t::has_compatible_value_v<U>; }
800 template <
typename OQ>
824 template <
typename U>
834 template <
typename... Args>
836 {
return out << q.
value() <<
" " << q.
unit(); }
861 template <
typename U,
typename T>
864 template <
typename U,
typename T>
867 template <
typename U,
typename T>
870 template <
typename U,
typename T>
877 template <
typename U,
typename T,
typename OT>
883 template <
typename U,
typename T,
typename OT>
888 {
return q * factor; }
893 template <
typename AU,
typename AT,
typename BU,
typename BT>
895 -> decltype(std::declval<AT>() * std::declval<BT>())
901 template <
typename U,
typename T,
typename OT>
920 template <
typename Unit,
typename Ratio,
typename T>
926 template <
typename Q,
typename R,
typename T =
typename Q::value_t>
939 template <
typename... Args>
948 template <
typename... Args>
1007 namespace prefixes {
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
1078 template <
typename Quantity>
1081 template <
typename Quantity>
1084 template <
typename Quantity>
1093 {
using std::runtime_error::runtime_error; };
1097 {
using std::runtime_error::runtime_error; };
1101 {
using std::runtime_error::runtime_error; };
1105 {
using std::runtime_error::runtime_error; };
1109 {
using std::runtime_error::runtime_error; };
1126 template <std::
intmax_t Num, std::
intmax_t Den>
1128 {
using type = std::ratio<Den, Num>; };
1132 template <std::
intmax_t Num, std::
intmax_t Den>
1134 static constexpr
auto gcd = boost::integer::gcd(Num, Den);
1140 template <
typename U,
typename Enable =
void>
1143 template <
typename U>
1145 <U,
std::enable_if_t<util::always_true_v<typename U::unit_t>>>
1146 :
public std::true_type
1149 template <
typename U>
1154 template <
typename Q>
1157 template <
typename... Args>
1162 template <
typename Q,
typename Enable =
void>
1165 template <
typename Q>
1167 <Q, std::enable_if_t<util::always_true_v<typename Q::quantity_t>>>
1168 :
public std::true_type
1171 template <
typename Q>
1176 template <
typename T,
typename =
void>
1181 template <
typename T>
1185 <(has_unit_v<T> && util::always_true_v<typename T::value_t>)>
1192 template <
typename T>
1197 template <
typename T,
typename Q>
1203 template <
typename T,
typename U>
1210 template <
typename Q>
1211 class numeric_limits:
public std::numeric_limits<typename Q::value_t> {
1223 {
return quantity_t{ value_traits_t::lowest() }; }
1225 {
return quantity_t{ value_traits_t::epsilon() }; }
1227 {
return quantity_t{ value_traits_t::round_error() }; }
1229 {
return quantity_t{ value_traits_t::infinity() }; }
1231 {
return quantity_t{ value_traits_t::quiet_NaN() }; }
1233 {
return quantity_t{ value_traits_t::signaling_NaN() }; }
1235 {
return quantity_t{ value_traits_t::denorm_min() }; }
1249 template <
typename R>
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>>())
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;
1280 return Long?
"???"sv:
"?"sv;
1287 template <
typename U,
typename T>
1288 template <
typename OU,
typename OT>
1294 "Only quantities with exactly the same unit can be added." 1301 template <
typename U,
typename T>
1302 template <
typename OU,
typename OT>
1308 "Only quantities with exactly the same unit can be subtracted." 1315 template <
typename U,
typename T>
1316 template <
typename OU,
typename OT>
1322 (sameBaseUnitAs<OU>(),
"Can't add quantities with different base unit");
1325 if constexpr (sameUnitAs<OU>()) {
1337 template <
typename U,
typename T>
1338 template <
typename OU,
typename OT>
1344 (sameBaseUnitAs<OU>(),
"Can't subtract quantities with different base unit");
1347 if constexpr (sameUnitAs<OU>()) {
1359 template <
typename U,
typename T>
1360 template <
typename OU,
typename OT>
1366 (sameBaseUnitAs<OU>(),
"Can't divide quantities with different base unit");
1369 if constexpr (sameUnitAs<OU>()) {
1370 return value() / q.value();
1380 template <
typename U,
typename T>
1381 template <
typename OU,
typename OT>
1387 (sameBaseUnitAs<OU>(),
"Can't add quantities with different base unit");
1390 if constexpr (sameUnitAs<OU>()) {
1391 fValue += other.
value();
1402 template <
typename U,
typename T>
1403 template <
typename OU,
typename OT>
1408 static_assert(sameBaseUnitAs<OU>(),
1409 "Can't subtract quantities with different base unit" 1413 if constexpr (sameUnitAs<OU>()) {
1414 fValue -= other.
value();
1425 template <
typename U,
typename T>
1426 template <
typename OU,
typename OT>
1431 (sameBaseUnitAs<OU>(),
"Can't compare quantities with different base unit");
1434 if constexpr (sameUnitAs<OU>()) {
1445 template <
typename U,
typename T>
1446 template <
typename OU,
typename OT>
1447 constexpr
bool util::quantities::concepts::Quantity<U, T>::operator!=
1451 (sameBaseUnitAs<OU>(),
"Can't compare quantities with different base unit");
1454 if constexpr (sameUnitAs<OU>()) {
1465 template <
typename U,
typename T>
1466 template <
typename OU,
typename OT>
1467 constexpr
bool util::quantities::concepts::Quantity<U, T>::operator<=
1471 (sameBaseUnitAs<OU>(),
"Can't compare quantities with different base unit");
1474 if constexpr (sameUnitAs<OU>()) {
1485 template <
typename U,
typename T>
1486 template <
typename OU,
typename OT>
1487 constexpr
bool util::quantities::concepts::Quantity<U, T>::operator>=
1491 (sameBaseUnitAs<OU>(),
"Can't compare quantities with different base unit");
1494 if constexpr (sameUnitAs<OU>()) {
1505 template <
typename U,
typename T>
1506 template <
typename OU,
typename OT>
1507 constexpr
bool util::quantities::concepts::Quantity<U, T>::operator<
1511 (sameBaseUnitAs<OU>(),
"Can't compare quantities with different base unit");
1514 if constexpr (sameUnitAs<OU>()) {
1525 template <
typename U,
typename T>
1526 template <
typename OU,
typename OT>
1527 constexpr
bool util::quantities::concepts::Quantity<U, T>::operator>
1531 (sameBaseUnitAs<OU>(),
"Can't compare quantities with different base unit");
1534 if constexpr (sameUnitAs<OU>()) {
1558 template <
typename Quantity>
1559 std::pair<std::string, typename Quantity::value_t>
readUnit 1566 template <
typename Quantity>
1567 std::pair<std::string, typename Quantity::value_t>
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;
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, 1
e-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 }
1600 static auto const composePrefixPattern = [](
auto b,
auto e) ->
std::string 1604 pattern +=
b->first;
1605 while (++
b != e) { pattern +=
'|'; pattern +=
b->first; }
1607 return pattern +=
")";
1610 = composePrefixPattern(factors.begin(), factors.end());
1613 std::regex
const unitPattern {
1614 "[[:blank:]]*(" + prefixPattern +
"?" 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 '" 1625 return {
str, value_t{ 1 } };
1633 auto const iFactor = factors.
find(unitMatch.str(2U));
1634 if (iFactor == factors.end()) {
1636 "Unit '" + unitMatch.str(1U)
1637 +
"' has unsupported prefix '" + unitMatch.str(2U)
1638 +
"' (parsing '" + str +
"')" 1643 str.substr(0U, str.length() - unitMatch.length()),
1644 static_cast<value_t>(unit_t::scale(iFactor->second))
1651 template <
typename Quantity>
1661 auto const [ num_s, factor ] = details::readUnit<Quantity>(
s, unitOptional);
1663 char* parseEnd =
nullptr;
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!");
1670 while (parseEnd != send) {
1671 if (!std::isblank(static_cast<unsigned char>(*parseEnd))) {
1683 return Quantity{
static_cast<value_t
>(
value * factor) };
1688 template <
typename Quantity>
1690 (std::string_view s,
bool unitOptional )
1692 return util::quantities::makeQuantity<Quantity>
1693 (
std::string{ s.begin(), s.end() }, unitOptional);
1698 template <
typename Quantity>
1700 (
char const* s,
bool unitOptional )
1703 util::quantities::makeQuantity<Quantity>(std::string_view{s}, unitOptional);
1714 template <
typename... Args>
1715 struct hash<
util::quantities::concepts::Quantity<Args...>> {
1722 noexcept(noexcept(std::hash<value_t>()(
key.value())))
1723 {
return std::hash<value_t>()(
key.value()); }
1729 template <
typename Unit,
typename T>
1730 class numeric_limits<
util::quantities::concepts::Quantity<Unit, T>>
1732 <util::quantities::concepts::Quantity<Unit, T>>
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>
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>
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>
1764 #endif // LARDATAALG_UTILITIES_QUANTITIES_H
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
DoubleProduct & operator+=(DoubleProduct &left, DoubleProduct const &right)
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
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.
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.
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.
int find(char c, int index=0, bool cs=TRUE) const
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
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.
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.
static int max(int a, int b)
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
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
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
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.
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 std::vector< std::string > const names
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.
static constexpr quantity_t infinity() noexcept