// // Units.h // // Library: Util // Package: Units // Module: Units // // Definitions for the C++ Units library. // // Copyright (c) 2007-2010, Applied Informatics Software Engineering GmbH. // and Contributors. // // SPDX-License-Identifier: BSL-1.0 // // Adapted for POCO from the following source: // // C++ Units by Calum Grant // // Written by Calum Grant // Copyright (C) Calum Grant 2007 // // Home page: http://calumgrant.net/units // File location: http://calumgrant.net/units/units.hpp // Manual: http://calumgrant.net/units/units.html // // Copying permitted under the terms of the Boost software license. // #ifndef Util_Units_INCLUDED #define Util_Units_INCLUDED #include "Poco/Util/Util.h" #include namespace Poco { namespace Util { namespace Units { namespace Internal { template struct Convert; struct None; template struct FixedPower; } template struct Compose; /// Construct a unit equivalent to Unit1*Unit2 template struct Scale; /// Constructs a unit equivalent to U*Num/Den template struct Translate; /// Constructs a Unit equivalent to U+Num/Den template struct Power; /// Constructs a Unit equivalent to U^(Num/Den) typedef Power Unit; /// A unit which is effectively no units at all. template class Value /// A Value with a unit. /// - V is the type you are storing /// - U is the unit of the Value /// /// This class is usually not used directly; /// client code should use the typedef'd /// instantiations defined in the Values and /// Constants namespace. /// /// Example: /// /// using namespace Poco::Util::Units::Values; /// /// std::cout << "One mile is " << km(mile(1)) << std::endl; /// // Output: One mile is 1.60934 km /// /// std::cout << "Flow rate is " << m3(mile(1)*inch(80)*foot(9))/s(minute(5)); /// // Output: Flow rate is 29.9026 (m)^3.(s)^-1 /// /// hours h; /// h = cm(3); // Compile-time error: incompatible units /// h = 4; // Compile-time error: 4 of what? /// h = days(4); // Ok: h is 96 hours { public: typedef V ValueType; typedef U Unit; Value(): _rep() { } explicit Value(const ValueType& v): _rep(v) { } template Value(const Value& v): _rep(Internal::Convert::fn(v.get())) { } const ValueType& get() const { return _rep; } template Value& operator = (const Value& other) { _rep = Value(other).get(); return *this; } template Value operator + (const Value& other) const { return Value(get() + Value(other).get()); } template Value& operator += (const Value& other) { _rep += Value(other).get(); return *this; } template Value& operator -= (const Value& other) { _rep -= Value(other).get(); return *this; } template Value operator - (const Value& other) const { return Value(get() - Value(other).get()); } Value operator - () const { return Value(-get()); } template Value > operator * (const Value& other) const { return Value >(get() * other.get()); } Value operator * (const ValueType& v) const { return Value(get() * v); } Value& operator *= (const ValueType& v) { _rep *= v; return *this; } template Value > > operator / (const Value& other) const { return Value > >(get() / other.get()); } Value operator / (const ValueType& v) const { return Value(get() / v); } Value& operator /= (const ValueType& v) { _rep /= v; return *this; } template bool operator == (const Value& other) const { return get() == Value(other).get(); } template bool operator != (const Value& other) const { return get() != Value(other).get(); } template bool operator < (const Value& other) const { return get() < Value(other).get(); } template bool operator <= (const Value& other) const { return get() <= Value(other).get(); } template bool operator > (const Value& other) const { return get() > Value(other).get(); } template bool operator >= (const Value& other) const { return get() >= Value(other).get(); } Value& operator ++ () { ++_rep; return *this; } Value operator ++ (int) { Value v = *this; ++_rep; return v; } Value& operator -- () { --_rep; return *this; } Value operator -- (int) { Value v = *this; --_rep; return v; } private: ValueType _rep; }; template Value > operator / (const V& a, const Value& b) { return Value >(a / b.get()); } template Value operator * (const V& a, const Value& b) { return Value(a * b.get()); } template Value > sqrt(const Value& a) { return Value >(std::sqrt(a.get())); } template Value > square(const Value& a) { return Value >(std::pow(a.get(), 2)); } template Value > cube(const Value& a) { return Value >(std::pow(a.get(), 3)); } template Value > raise(const Value& a) { return Value >(Internal::FixedPower::Power(a.get())); } namespace Internal { template struct Convertible; template struct ScalingFactor; template struct Convert3 /// Converts T1 to T2. /// Stage 3 - performed after Stage 1 and Stage 2. /// The reason we perform Convert in stages is so that the compiler /// can resolve templates in the order we want it to. { template static V fn(const V& v) /// The default implementation assumes that the two quantities are in compatible /// Units up to some scaling factor. Find the scaling factor and apply it. { return v * ScalingFactor::template fn() / ScalingFactor::template fn(); } }; template struct Convert2 /// Converts T1 to T2. /// Template matches the first argument (T1), /// this is the fall-through to Convert3. { template static V fn(const V& v) { return Convert3::fn(v); } }; template struct Convert /// Converts T1 to T2. /// If you really want to implement your own conversion routine, /// specialize this template. /// The default implementation falls through to Convert2. { /// If this fails, then T1 is not Convertible to T2: poco_static_assert ((Convertible::Value)); template static V fn(const V& v) { return Convert2::fn(v); } }; template struct Convert // Trivial conversion to the same type. { template static const U& fn(const U& u) { return u; } }; template struct Convert3 // Convert to same type. { template static const U& fn(const U& u) { return u; } }; template struct Convert2, U> // Convert from a scaled Unit. { template static V fn(const V& v) { return Convert::fn((v * Den)/Num); } }; template struct Convert3 > // Convert to a scaled Unit. { template static V fn(const V& v) { return (Convert::fn(v) * Num)/ Den; } }; template struct Convert2, U> // Convert from a translated Unit. { template static V fn(const V& v) { return Convert::fn(v - static_cast(Num) / static_cast(Den)); } }; template struct Convert3 > // Convert to a translated Unit. { template static V fn(const V& v) { return Convert::fn(v) + static_cast(Num) / static_cast(Den); } }; template struct CountTerms /// Count the power to which Unit Term is raised in the Unit List. /// Returns a rational num/den of the power of term Term in List. /// The default assumes that Term is not found (num/den=0). { static const int num = 0; static const int den = 1; }; template struct CountTerms { static const int num = 1; static const int den = 1; }; template struct CountTerms > // CountTerms ignores scaling factors - that is taken care of by ScalingFactor. { typedef CountTerms result; static const int num = result::num; static const int den = result::den; }; template struct CountTerms > // CountTerms ignores translation. { typedef CountTerms result; static const int num = result::num; static const int den = result::den; }; template struct CountTerms > // Addition of fractions. { typedef CountTerms result1; typedef CountTerms result2; static const int num = result1::num * result2::den + result1::den * result2::num; static const int den = result1::den * result2::den; }; template struct CountTerms > // Multiplication of fractions. { typedef CountTerms result; static const int num = N * result::num; static const int den = D * result::den; }; template struct CheckTermsEqual /// Counts the power of the Unit Term in Units T1 and T2. /// Reports if they are equal, using equality of fractions. /// Does a depth-first search of the Unit "Term", /// or counts the terms in the default case. { typedef CountTerms count1; typedef CountTerms count2; static const bool Value = count1::num * count2::den == count1::den * count2::num; }; template struct CheckTermsEqual, T1, T2 > { static const bool Value = CheckTermsEqual::Value; }; template struct CheckTermsEqual, T1, T2 > { static const bool Value = CheckTermsEqual::Value; }; template struct CheckTermsEqual, T1, T2 > { static const bool Value = CheckTermsEqual::Value; }; template struct CheckTermsEqual,T3,T4> { static const bool Value = CheckTermsEqual::Value && CheckTermsEqual::Value; }; template struct Convertible /// Determines whether two types are Convertible. /// Counts the powers in the LHS and RHS and ensures they are equal. { static const bool Value = CheckTermsEqual::Value && CheckTermsEqual::Value; }; template struct FixedPower /// A functor that raises a Value to the power Num/Den. /// The template is specialised for efficiency /// so that we don't always have to call the std::power function. { template static T Power(const T& t) { return std::pow(t, static_cast(Num)/static_cast(Den)); } }; template struct FixedPower { template static const T& Power(const T& t) { return t; } }; template struct FixedPower { template static T Power(const T& t) { return t*t; } }; template struct FixedPower { template static T Power(const T& t) { return t*t*t; } }; template struct FixedPower { template static const T& Power(const T& t) { T u = t*t; return u*u; } }; template struct FixedPower { template static T Power(const T& t) { return 1/t; } }; template struct FixedPower { template static T Power(const T& t) { return 1/(t*t); } }; template struct FixedPower { template static T Power(const T& t) { return 1; } }; template struct ScalingFactor /// Determine the scaling factor of a Unit in relation to its "base" Units. /// Default is that U is a primitive Unit and is not scaled. { template static T fn() { return 1; } }; template struct ScalingFactor< Compose > { template static T fn() { return ScalingFactor::template fn() * ScalingFactor::template fn(); } }; template struct ScalingFactor< Scale > { template static T fn() { return ScalingFactor::template fn() * static_cast(N) / static_cast(D); } }; template struct ScalingFactor< Power > { template static T fn() { return FixedPower::Power(ScalingFactor::template fn()); } }; template struct ScalingFactor< Translate > { template static T fn() { return ScalingFactor::template fn(); } }; } // namespace Internal /// /// Display /// #define UNIT_DISPLAY_NAME(Unit, string) \ template <> \ struct OutputUnit \ { \ template \ static void fn(Stream& os) \ { \ os << string; \ } \ } namespace Internal { template struct OutputUnit2 /// The default Unit formatting mechanism. { template static void fn(Stream &os) { os << "Units"; } }; } template struct OutputUnit /// Functor to write Unit text to stream. { template static void fn(Stream &os) { Internal::OutputUnit2::fn(os); } }; UNIT_DISPLAY_NAME(Unit, "1"); namespace Internal { template struct OutputUnit2< Compose > { template static void fn(Stream &os) { OutputUnit::fn(os); os << '.'; OutputUnit::fn(os); } }; template struct OutputUnit2< Power > { template static void fn(Stream &os) { if(Num!=Den) os << '('; OutputUnit::fn(os); if(Num!=Den) { os << ')'; os << '^' << Num; if(Num%Den) { os << '/' << Den; } } } }; template struct OutputUnit2< Translate > { template static void fn(Stream &os) { os << '('; OutputUnit::fn(os); os << '+' << Num; if(Den!=1) os << '/' << Den; os << ')'; } }; template struct OutputUnit2< Scale > { template static void fn(Stream &os) { os << Den; if(Num != 1) os << '/' << Num; os << '.'; OutputUnit::fn(os); } }; } // namespace Internal template Str& operator << (Str& os, const Value& value) { os << value.get() << ' '; OutputUnit::fn(os); return os; } /// /// Additional Units /// namespace Units { typedef Poco::Util::Units::Unit Unit; // SI base Units: struct m; /// meter struct kg; /// kilogram struct s; /// second struct K; /// Kelvin struct A; /// Ampere struct mol; /// mole struct cd; /// candela } UNIT_DISPLAY_NAME(Units::m, "m"); UNIT_DISPLAY_NAME(Units::kg, "kg"); UNIT_DISPLAY_NAME(Units::s, "s"); UNIT_DISPLAY_NAME(Units::K, "K"); UNIT_DISPLAY_NAME(Units::A, "A"); UNIT_DISPLAY_NAME(Units::mol, "mol"); UNIT_DISPLAY_NAME(Units::cd, "cd"); namespace Units { // SI derived Units: typedef Compose > rad; typedef Compose, Power > sr; typedef Power Hz; typedef Compose > > N; typedef Compose > Pa; typedef Compose J; typedef Compose > W; typedef Compose C; typedef Compose > V; typedef Compose > F; typedef Compose > Ohm; typedef Compose > S; typedef Compose Wb; typedef Compose > T; typedef Compose > H; typedef cd lm; typedef Compose > lx; typedef Power Bq; typedef Compose > Gy; typedef Gy Sv; typedef Compose,mol> kat; } UNIT_DISPLAY_NAME(Units::rad, "rad"); UNIT_DISPLAY_NAME(Units::sr, "sr"); // UNIT_DISPLAY_NAME(Units::Hz, "Hz"); // Too problematic UNIT_DISPLAY_NAME(Units::N, "N"); UNIT_DISPLAY_NAME(Units::Pa, "Pa"); UNIT_DISPLAY_NAME(Units::J, "J"); UNIT_DISPLAY_NAME(Units::W, "W"); UNIT_DISPLAY_NAME(Units::C, "C"); UNIT_DISPLAY_NAME(Units::V, "V"); UNIT_DISPLAY_NAME(Units::F, "F"); UNIT_DISPLAY_NAME(Units::Ohm, "Ohm"); UNIT_DISPLAY_NAME(Units::S, "S"); UNIT_DISPLAY_NAME(Units::Wb, "Wb"); UNIT_DISPLAY_NAME(Units::T, "T"); UNIT_DISPLAY_NAME(Units::H, "H"); UNIT_DISPLAY_NAME(Units::lx, "lx"); UNIT_DISPLAY_NAME(Units::Gy, "Gy"); UNIT_DISPLAY_NAME(Units::kat, "kat"); namespace Units { // SI prefixes: template struct deca { typedef Scale type; }; template struct hecto { typedef Scale type; }; template struct kilo { typedef Scale type; }; template struct mega { typedef Scale::type, 1, 1000> type; }; template struct giga { typedef Scale::type, 1, 1000> type; }; template struct tera { typedef Scale::type, 1, 1000> type; }; template struct peta { typedef Scale::type, 1, 1000> type; }; template struct exa { typedef Scale::type, 1, 1000> type; }; template struct zetta { typedef Scale::type, 1, 1000> type; }; template struct yotta { typedef Scale::type, 1, 1000> type; }; template struct deci { typedef Scale type; }; template struct centi { typedef Scale type; }; template struct milli { typedef Scale type; }; template struct micro { typedef Scale::type, 1000> type; }; template struct nano { typedef Scale::type, 1000> type; }; template struct pico { typedef Scale::type, 1000> type; }; template struct femto { typedef Scale::type, 1000> type; }; template struct atto { typedef Scale::type, 1000> type; }; template struct zepto { typedef Scale::type, 1000> type; }; template struct yocto { typedef Scale::type, 1000> type; }; // Some prefixed SI Units: typedef centi::type cm; typedef milli::type mm; typedef kilo::type km; typedef milli::type g; typedef milli::type mg; typedef milli::type ms; class Prefix /// Parent class for unit prefixes. /// Use classes inheriting from this class to scale /// the values. { public: template Prefix(const T& val, double multiplier = 1, const std::string& prefix = ""): _pHolder(new Holder(val)), _multiplier(multiplier), _prefix(prefix) { } double value() const { return _pHolder->get() * _multiplier; } void addPrefix(std::ostream& os) const { os << _prefix; } void addUnit(std::ostream& os) const { _pHolder->appendUnit(os); } private: Prefix(); class Placeholder { public: virtual ~Placeholder() { } virtual double get() const = 0; virtual void appendUnit(std::ostream& os) const = 0; }; template struct Holder : public Placeholder { typedef Value ValueType; Holder (const U& val): _val(ValueType(val)) { } double get() const { return _val.get(); } void appendUnit(std::ostream& os) const { OutputUnit::fn(os); } ValueType _val; }; Placeholder* _pHolder; double _multiplier; std::string _prefix; }; } template Str& streamOp (Str& os, const Units::Prefix& val) { os << val.value() << ' '; val.addPrefix(os); val.addUnit(os); return os; } template Str& operator << (Str& os, const Units::Prefix& val) /// Streaming operator for prefixed values. { return streamOp(os, val); } UNIT_DISPLAY_NAME(Units::cm, "cm"); UNIT_DISPLAY_NAME(Units::mm, "mm"); UNIT_DISPLAY_NAME(Units::km, "km"); UNIT_DISPLAY_NAME(Units::g, "g"); UNIT_DISPLAY_NAME(Units::mg, "mg"); UNIT_DISPLAY_NAME(Units::ms, "ms"); namespace Units { // Non-SI mass typedef Scale lb; typedef Scale oz; typedef Scale tonne; // Non-SI temperature typedef Translate Celsius; typedef Translate, 32> Fahrenheit; // Non-SI time typedef Scale minute; typedef Scale hour; typedef Scale day; typedef Scale week; struct month; // No fixed ratio with week typedef Scale year; typedef Scale century; typedef Scale millennium; // Non-SI length typedef Scale inch; typedef Scale foot; typedef Scale yard; typedef Scale mile; typedef Scale nautical_mile; // Non-SI area typedef Power m2; typedef Power mm2; typedef Scale hectare; typedef Scale are; typedef Power inch2; typedef Scale acre; // Non-SI volume typedef Power cm3; typedef cm3 ml; typedef Scale liter; typedef Scale dl; typedef Scale cl; typedef Power m3; // Non-SI velocity typedef Compose > mph; typedef Compose > kph; typedef Compose > meters_per_second; typedef Compose > knot; typedef Scale mach; // Angles typedef Scale degree; typedef Scale grad; typedef Scale< degree, 60 > degree_minute; typedef Scale< degree_minute, 60 > degree_second; // Pressure typedef Scale kPa; typedef Scale psi; typedef Scale millibar; // Other typedef Scale rpm; typedef Scale percent; typedef Scale dozen; typedef Scale bakers_dozen; } UNIT_DISPLAY_NAME(Units::lb, "lb"); UNIT_DISPLAY_NAME(Units::oz, "oz"); UNIT_DISPLAY_NAME(Units::tonne, "tonnes"); UNIT_DISPLAY_NAME(Units::Celsius, "'C"); UNIT_DISPLAY_NAME(Units::Fahrenheit, "'F"); UNIT_DISPLAY_NAME(Units::minute, "minutes"); UNIT_DISPLAY_NAME(Units::hour, "hours"); UNIT_DISPLAY_NAME(Units::day, "days"); UNIT_DISPLAY_NAME(Units::week, "weeks"); UNIT_DISPLAY_NAME(Units::month, "months"); UNIT_DISPLAY_NAME(Units::year, "years"); UNIT_DISPLAY_NAME(Units::century, "centuries"); UNIT_DISPLAY_NAME(Units::millennium, "millennia"); UNIT_DISPLAY_NAME(Units::inch, "inches"); UNIT_DISPLAY_NAME(Units::foot, "foot"); UNIT_DISPLAY_NAME(Units::yard, "yards"); UNIT_DISPLAY_NAME(Units::mile, "miles"); UNIT_DISPLAY_NAME(Units::nautical_mile, "nautical miles"); UNIT_DISPLAY_NAME(Units::hectare, "ha"); UNIT_DISPLAY_NAME(Units::are, "are"); UNIT_DISPLAY_NAME(Units::acre, "acres"); UNIT_DISPLAY_NAME(Units::ml, "ml"); UNIT_DISPLAY_NAME(Units::liter, "l"); UNIT_DISPLAY_NAME(Units::dl, "dl"); UNIT_DISPLAY_NAME(Units::cl, "cl"); UNIT_DISPLAY_NAME(Units::mph, "mph"); UNIT_DISPLAY_NAME(Units::kph, "km/h"); UNIT_DISPLAY_NAME(Units::knot, "knots"); UNIT_DISPLAY_NAME(Units::mach, "mach"); UNIT_DISPLAY_NAME(Units::degree, "deg"); UNIT_DISPLAY_NAME(Units::grad, "grad"); UNIT_DISPLAY_NAME(Units::degree_minute, "'"); UNIT_DISPLAY_NAME(Units::degree_second, "\""); UNIT_DISPLAY_NAME(Units::kPa, "kPa"); UNIT_DISPLAY_NAME(Units::psi, "PSI"); UNIT_DISPLAY_NAME(Units::millibar, "millibars"); UNIT_DISPLAY_NAME(Units::percent, "%"); UNIT_DISPLAY_NAME(Units::rpm, "rpm"); UNIT_DISPLAY_NAME(Units::dozen, "dozen"); UNIT_DISPLAY_NAME(Units::bakers_dozen, "bakers dozen"); namespace Values { typedef Value Unit; // SI Units typedef Value m; typedef Value kg; typedef Value s; typedef Value K; typedef Value A; typedef Value mol; typedef Value cd; // SI derived typedef Value rad; typedef Value sr; typedef Value Hz; typedef Value N; typedef Value Pa; typedef Value J; typedef Value W; typedef Value C; typedef Value V; typedef Value F; typedef Value Ohm; typedef Value S; typedef Value Wb; typedef Value T; typedef Value H; typedef Value lm; typedef Value lx; typedef Value Bq; typedef Value Gy; typedef Value Sv; typedef Value kat; // Prefixed Units typedef Value cm; typedef Value mm; typedef Value km; typedef Value g; typedef Value mg; typedef Value ms; // Non-SI typedef Value lb; typedef Value oz; typedef Value tonne; typedef Value Celsius; typedef Value Fahrenheit; typedef Value minute; typedef Value hour; typedef Value day; typedef Value week; typedef Value month; typedef Value year; typedef Value century; typedef Value millennium; typedef Value inch; typedef Value foot; typedef Value yard; typedef Value mile; typedef Value nautical_mile; typedef Value m2; typedef Value mm2; typedef Value hectare; typedef Value are; typedef Value inch2; typedef Value acre; typedef Value cm3; typedef Value ml; typedef Value cl; typedef Value liter; typedef Value dl; typedef Value m3; typedef Value mph; typedef Value kph; typedef Value meters_per_second; typedef Value knot; typedef Value mach; typedef Value degree; typedef Value grad; typedef Value degree_minute; typedef Value degree_second; typedef Value kPa; typedef Value psi; typedef Value millibar; typedef Value percent; typedef Value rpm; typedef Value dozen; typedef Value bakers_dozen; #define DEFINE_PREFIX_CLASS(name, scale, prefix) \ struct name: public Units::Prefix \ { \ template \ name(const T& val): Prefix(val, scale, prefix) \ { \ } \ }; \ template \ Str& operator << (Str& os, const name& val) \ { \ return streamOp(os, val); \ } DEFINE_PREFIX_CLASS (deca, .1, "da") DEFINE_PREFIX_CLASS (hecto, .01, "h") DEFINE_PREFIX_CLASS (kilo, .001, "k") DEFINE_PREFIX_CLASS (mega, 1e-6, "M") DEFINE_PREFIX_CLASS (giga, 1e-9, "G") DEFINE_PREFIX_CLASS (tera, 1e-12, "T") DEFINE_PREFIX_CLASS (peta, 1e-15, "P") DEFINE_PREFIX_CLASS (exa, 1e-18, "E") DEFINE_PREFIX_CLASS (zetta, 1e-21, "Z") DEFINE_PREFIX_CLASS (yotta, 1e-24, "Y") DEFINE_PREFIX_CLASS (deci, 10, "d") DEFINE_PREFIX_CLASS (centi, 100, "c") DEFINE_PREFIX_CLASS (milli, 1000, "m") DEFINE_PREFIX_CLASS (micro, 1e6, "u") DEFINE_PREFIX_CLASS (nano, 1e9, "n") DEFINE_PREFIX_CLASS (pico, 1e12, "p") DEFINE_PREFIX_CLASS (femto, 1e15, "f") DEFINE_PREFIX_CLASS (atto, 1e18, "a") DEFINE_PREFIX_CLASS (zepto, 1e21, "z") DEFINE_PREFIX_CLASS (yocto, 1e24, "y") } namespace Constants { // Physical constants: const Value > > k (1.3806504e-23); const Value mu (1.660538782e-27); const Value > NA (6.02214179e23); const Value G0 (7.7480917004e-5); const Value > > e0 (8.854187817e-12); const Value me (9.10938215e-31); const Value eV (1.602176487e-19); const Value e (1.602176487e-19); const Value F (96485.3399); const Value alpha (7.2973525376e-3); const Value inv_alpha (137.035999679); const Value > > u0 (12.566370614); const Value phi0 (2.067833667e-15); // ?? const Value, Power > > > R (8.314472); const Value, Compose, Power > > > G (6.67428e-11); const Value > h (6.62606896e-34); const Value > h_bar (1.054571628e-34); const Value mp (1.672621637e-27); const Value mpme (1836.15267247); const Value > Rinf (10973731.568527); const Value > > c (299792458); const Value, Power > > > rho (5.6704e-8); // Other constants: const Value pi (3.141592653589793); const Value lightyear (9.4605284e15); const Value AU(149597871); const Value > > g (9.80665); } // // Trigonometry // template V sin(const Value& angle) { return std::sin(Value(angle).get()); } template V cos(const Value& angle) { return std::cos(Value(angle).get()); } template V tan(const Value& angle) { return std::tan(Value(angle).get()); } } } } // namespace Poco::Util::Units #endif // Util_Units_INCLUDED