From 412a0ba163c0f9c93f266a0e205cee732e6ead6f Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 22 May 2024 15:16:17 -0400 Subject: [PATCH] xo-unit: kitchen-sink doc + build improvements + 1 bug fix --- CMakeLists.txt | 10 +- docs/CMakeLists.txt | 8 +- docs/basis-unit-class.rst | 46 ++++- docs/basis-unit-constants.rst | 32 +++- docs/basis-unit-reference.rst | 39 ++-- docs/bpu-class.rst | 48 +++-- docs/bu-store-class.rst | 31 +-- docs/development.rst | 10 +- docs/dimension-enum.rst | 68 +++++-- docs/examples.rst | 132 +++++++++---- docs/implementation.rst | 84 +++++++-- docs/index.rst | 6 +- docs/install.rst | 292 ++++++++++++++++++++++++++--- docs/natural-unit-class.rst | 103 ++++++++-- docs/quantity-class.rst | 54 +++++- docs/quantity-factoryfunctions.rst | 50 +++++ docs/scaled-unit-class.rst | 114 ++++++++++- docs/scaled-unit-constants.rst | 75 ++++++++ docs/scaled-unit-reference.rst | 31 +++ docs/unit-concept.rst | 12 -- docs/unit-quantities.rst | 93 --------- docs/unit-reference.rst | 10 - docs/xquantity-class.rst | 15 ++ docs/xquantity-reference.rst | 27 +++ example/CMakeLists.txt | 2 + example/ex1/CMakeLists.txt | 12 +- example/ex2/CMakeLists.txt | 12 +- example/ex3/CMakeLists.txt | 12 +- example/ex3/ex3.cpp | 2 - example/ex4/CMakeLists.txt | 12 +- example/ex4/ex4.cpp | 1 - example/ex5/CMakeLists.txt | 12 +- example/ex6/CMakeLists.txt | 12 +- example/ex7/CMakeLists.txt | 12 +- example/ex8/CMakeLists.txt | 12 ++ example/ex8/ex8.cpp | 29 +++ example/ex_su/CMakeLists.txt | 12 ++ example/ex_su/ex_su.cpp | 38 ++++ include/xo/unit/basis_unit.hpp | 67 ++++++- include/xo/unit/bpu.hpp | 39 ++-- include/xo/unit/natural_unit.hpp | 101 ++++++++-- include/xo/unit/quantity.hpp | 173 ++++++++++++++--- include/xo/unit/scaled_unit.hpp | 224 ++++++++++++++++------ include/xo/unit/xquantity.hpp | 10 + utest/CMakeLists.txt | 14 +- 45 files changed, 1719 insertions(+), 479 deletions(-) create mode 100644 docs/scaled-unit-constants.rst create mode 100644 docs/scaled-unit-reference.rst delete mode 100644 docs/unit-concept.rst delete mode 100644 docs/unit-quantities.rst delete mode 100644 docs/unit-reference.rst create mode 100644 docs/xquantity-class.rst create mode 100644 docs/xquantity-reference.rst create mode 100644 example/ex8/CMakeLists.txt create mode 100644 example/ex8/ex8.cpp create mode 100644 example/ex_su/CMakeLists.txt create mode 100644 example/ex_su/ex_su.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 18c22842..6cfe5a99 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,15 +7,7 @@ project(xo_unit VERSION 1.0) include(GNUInstallDirs) include(cmake/xo-bootstrap-macros.cmake) -xo_cxx_toplevel_options2() - -# ---------------------------------------------------------------- -# cmake -DCMAKE_BUILD_TYPE=debug -xo_toplevel_debug_config2() - -# ---------------------------------------------------------------- -# cmake -DCMAKE_BUILD_TYPE=coverage -xo_toplevel_coverage_config2() +xo_cxx_toplevel_options3() # ---------------------------------------------------------------- # c++ settings diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index 3e28a89e..e40b6800 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -5,9 +5,11 @@ xo_docdir_doxygen_config() xo_docdir_sphinx_config( index.rst examples.rst glossary.rst install.rst implementation.rst development.rst quantity-reference.rst quantity-class.rst quantity-factoryfunctions.rst quantity-unitvars.rst - unit-reference.rst unit-concept.rst unit-quantities.rst - scaled-unit-class.rst natural-unit-class.rst - bpu-class.rst bu-store-class.rst basis-unit-reference.rst + xquantity-reference.rst xquantity-class.rst + scaled-unit-reference.rst scaled-unit-class.rst scaled-unit-constants.rst + natural-unit-class.rst + bpu-class.rst + bu-store-class.rst basis-unit-reference.rst basis-unit-class.rst basis-unit-constants.rst dimension-enum.rst ) diff --git a/docs/basis-unit-class.rst b/docs/basis-unit-class.rst index 26714c6f..01f0b231 100644 --- a/docs/basis-unit-class.rst +++ b/docs/basis-unit-class.rst @@ -3,16 +3,56 @@ Basis Unit ========== +A unit representing a fixed multiple of a native dimension. + +Context +------- + +.. ditaa:: + :--scale: 0.85 + + +----------------+---------------+ + | quantity | xquantity | + +----------------+---------------+ + | scaled_unit | + +--------------------------------+ + | natural_unit | + +--------------------------------+ + | bpu | + +----------------+ | + | bu_store | | + +----------------+---------------+ + |cYEL basis_unit | + +--------------------------------+ + | dimension | + +--------------------------------+ + +Introduction +------------ + +A :code:`basis_unit` represents a unit belonging to a single native dimension. +For example :code:`bu::meter` representing a distance of 1 meter. + .. code-block:: cpp #include +.. uml:: + :scale: 99% + :align: center + :caption: basis unit representing 1 minute + + object bu1<> + bu1 : native_dim = time + bu1 : scalefactor = 60 + +:code:`basis_unit` is intended as an implementation-level abstraction. +Application code will normally interact with the more-capable :code:`scaled_unit` +instead of :code:`basis_unit`. + Class ----- -A :code:`basis_unit` represents a unit belonging to a single native dimension. -For example :code:`bu::meter` representing a distance of 1 meter. - .. doxygenclass:: xo::qty::basis_unit Member Variables diff --git a/docs/basis-unit-constants.rst b/docs/basis-unit-constants.rst index 78066abf..15bdc555 100644 --- a/docs/basis-unit-constants.rst +++ b/docs/basis-unit-constants.rst @@ -3,10 +3,38 @@ Basis Unit Constants ==================== -These constants represent low-level building blocks. +Relative scalefactors for each built-in unit. + +Context +------- + +.. ditaa:: + :--scale: 0.85 + + +----------------+---------------+ + | quantity | xquantity | + +----------------+---------------+ + | scaled_unit | + +--------------------------------+ + | natural_unit | + +--------------------------------+ + | bpu | + +----------------+ | + | bu_store | | + +----------------+---------------+ + |cYEL basis_unit | + +--------------------------------+ + | dimension | + +--------------------------------+ + +Introduction +------------ + +Constants in the :code:`xo::qty::detail::bu` namespace represent +low-level building blocks for specifying units. Relative scalefactors for each unit are chosen here. -Application code will not use this class directly; +Application code will not typically use these values directtly; instead it's expected to use units from the :code:`xo::qty::u` namespace. Those units are implemented on top of the basis units described here. diff --git a/docs/basis-unit-reference.rst b/docs/basis-unit-reference.rst index acf18e14..a026f00e 100644 --- a/docs/basis-unit-reference.rst +++ b/docs/basis-unit-reference.rst @@ -3,26 +3,29 @@ Basis Unit Reference ==================== -.. ditaa:: +Built-in named units for each native dimension - +-----------+-----------+ - | quantity | xquantity | - +-----------+-----------+ - | scaled_unit | - +-----------------------+ - | natural_unit | - +-----------------------+ - | bpu | - +-----------+ | - | bu_store | | - +-----------+-----------+ - |cYEL basis_unit | - +-----------------------+ - | dimension | - +-----------------------+ +.. ditaa:: + :--scale: 0.85 + + +----------------+---------------+ + | quantity | xquantity | + +----------------+---------------+ + | scaled_unit | + +--------------------------------+ + | natural_unit | + +--------------------------------+ + | bpu | + +----------------+ | + | bu_store | | + +----------------+---------------+ + |cYEL basis_unit | + +--------------------------------+ + | dimension | + +--------------------------------+ .. toctree:: - :maxdepth: 2 + :maxdepth: 1 - basis-unit-class + Basis Unit Class basis-unit-constants diff --git a/docs/bpu-class.rst b/docs/bpu-class.rst index 4d501d12..1706768e 100644 --- a/docs/bpu-class.rst +++ b/docs/bpu-class.rst @@ -3,23 +3,32 @@ BPU === -.. ditaa:: +A rational (usually integral) power of a single basis unit - +-----------+-----------+ - | quantity | xquantity | - +-----------+-----------+ - | scaled_unit | - +-----------------------+ - | natural_unit | - +-----------------------+ - |cYEL bpu | - +-------------+ | - | bu_store | | - +-------------+---------+ - | basis_unit | - +-----------------------+ - | dimension | - +-----------------------+ +Context +------- + +.. ditaa:: + :--scale: 0.85 + + +----------------+---------------+ + | quantity | xquantity | + +----------------+---------------+ + | scaled_unit | + +--------------------------------+ + | natural_unit | + +--------------------------------+ + |cYEL bpu | + +----------------+ | + | bu_store | | + +----------------+---------------+ + | basis_unit | + +--------------------------------+ + | dimension | + +--------------------------------+ + +Introduction +------------ .. code-block:: cpp @@ -49,6 +58,13 @@ For example: vol : scalefactor = 365*24*3600 vol : power = -1/2 +:code:`bpu` is intended as an implementation-level abstraction. +Application code will normally interact with the more-general :code:`scaled_unit` +instead of :code:`bpu`. + +Class +----- + .. doxygenclass:: xo::qty::bpu Member Variables diff --git a/docs/bu-store-class.rst b/docs/bu-store-class.rst index cf531dec..3214945a 100644 --- a/docs/bu-store-class.rst +++ b/docs/bu-store-class.rst @@ -4,22 +4,23 @@ Basis Unit Store ================ .. ditaa:: + :--scale: 0.85 - +-----------+-----------+ - | quantity | xquantity | - +-----------+-----------+ - | scaled_unit | - +-----------------------+ - | natural_unit | - +-----------------------+ - | bpu | - +-------------+ | - |cYEL bu_store| | - +-------------+---------+ - | basis_unit | - +-----------------------+ - | dimension | - +-----------------------+ + +----------------+---------------+ + | quantity | xquantity | + +----------------+---------------+ + | scaled_unit | + +--------------------------------+ + | natural_unit | + +--------------------------------+ + | bpu | + +----------------+ | + |cYEL bu_store | | + +----------------+---------------+ + | basis_unit | + +--------------------------------+ + | dimension | + +--------------------------------+ .. code-block:: cpp diff --git a/docs/development.rst b/docs/development.rst index 3b5d7207..d9695af4 100644 --- a/docs/development.rst +++ b/docs/development.rst @@ -1,12 +1,12 @@ .. _development: +Development +=========== + Miscellaneous development notes for *xo-unit*. -How To... -========= - -Add Basis Unit --------------- +Addding a Basis Unit +-------------------- To add a basis unit for an existing dimension: diff --git a/docs/dimension-enum.rst b/docs/dimension-enum.rst index e1dc4d24..15a62023 100644 --- a/docs/dimension-enum.rst +++ b/docs/dimension-enum.rst @@ -1,34 +1,66 @@ .. _dimension: -Dimension -========= +Native Dimension +================ + +An abstract dimension; distinct native dimensions are orthogonal + +Context +------- .. ditaa:: + :--scale: 0.85 - +-----------+-----------+ - | quantity | xquantity | - +-----------+-----------+ - | scaled_unit | - +-----------------------+ - | natural_unit | - +-----------------------+ - | bpu | - +-----------+ | - | bu_store | | - +-----------+-----------+ - | basis_unit | - +-----------------------+ - |cYEL dimension | - +-----------------------+ + +----------------+---------------+ + | quantity | xquantity | + +----------------+---------------+ + | scaled_unit | + +--------------------------------+ + | natural_unit | + +--------------------------------+ + | bpu | + +----------------+ | + | bu_store | | + +----------------+---------------+ + | basis_unit | + +--------------------------------+ + |cYEL dimension | + +--------------------------------+ + +Introduction +------------ + +Identifies an abstract dimension, for example *mass* or *time*. .. code-block:: cpp #include -Identifies an abstract dimension, for example *mass* or *time*. +For example can use this enum to index basis members of a :doc:`scaled_unit` instance: + +.. code-block:: cpp + :emphasize-lines: 7-8 + + #include + + using namespace xo::qty; + + auto x = q::kilometers(100) / q::hours(1); + + auto bpu1 = x.lookup_dim(dim::time); + auto bpu2 = x.lookup_dim(dim::distance); + +Enum +---- .. doxygenenum:: xo::qty::dimension +Constants +--------- + .. doxygenvariable:: xo::qty::n_dim +Functions +--------- + .. doxygenfunction:: xo::qty::dim2str diff --git a/docs/examples.rst b/docs/examples.rst index df7f5be3..292defb2 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -15,7 +15,7 @@ Units propagate through familiar arithmetic expressions: .. code-block:: cpp :linenos: - :emphasize-lines: 15-16 + :emphasize-lines: 14-15 #include "xo/unit/quantity.hpp" #include "xo/unit/quantity_iostream.hpp" @@ -25,7 +25,6 @@ Units propagate through familiar arithmetic expressions: main () { namespace q = xo::qty::qty; namespace su = xo::qty::su; - using xo::qty::quantity; using namespace std; constexpr auto t = q::minutes(2); @@ -40,7 +39,6 @@ Units propagate through familiar arithmetic expressions: << endl; } - with output: .. code-block:: @@ -101,29 +99,50 @@ See ``xo-unit/examples/ex2`` for code below. :linenos: :emphasize-lines: 10,13,16-17 - ... + #include "xo/unit/quantity.hpp" + #include "xo/unit/quantity_iostream.hpp" + #include - constexpr auto t = q::minutes(2); - constexpr auto d = q::kilometers(2.5); + int + main () { + namespace q = xo::qty::qty; + namespace u = xo::qty::u; + using xo::qty::with_units_from; + using xo::qty::with_units; + using xo::qty::quantity; + using xo::flatstring; + using namespace std; - constexpr auto t2 = t*t; - constexpr auto a = d / (t*t); + constexpr auto t = q::minutes(2); + constexpr auto d = q::kilometers(2.5); - // 1. - constexpr auto a2 = with_units(a); + constexpr auto t2 = t*t; + constexpr auto a = d / (t*t); - // 2. - constexpr auto a3 = a.rescale_ext(); + cerr << "t: " << t << ", d: " << d + << ", t^2: " << t2 + << ", d.t^-2: " << a + << endl; - // 3. - constexpr auto au = q::meter / (q::second * q::second); - constexpr auto a4 = with_units_from(a, au); // 3. + constexpr auto a2 = with_units(a); - static_assert(a2.abbrev() == flatstring("m.s^-2")); + static_assert(a2.abbrev() == flatstring("m.s^-2")); - cerr << "a2: " << a2 << endl; - cerr << "a3: " << a3 << endl; - cerr << "a4: " << a4 << endl; + cerr << "a2: " << a2 << endl; + + constexpr auto a3 = a.rescale_ext(); + + static_assert(a3.abbrev() == flatstring("m.s^-2")); + + cerr << "a3: " << a3 << endl; + + constexpr auto au = q::meter / (q::second * q::second); + constexpr auto a4 = with_units_from(a, au); + + static_assert(a4.abbrev() == flatstring("m.s^-2")); + + cerr << "a4: " << a4 << endl; + } with output: @@ -149,13 +168,11 @@ See ``xo-unit/example/ex3`` for code below int main () { namespace q = xo::qty::qty; - namespace nu = xo::qty::nu; - using xo::qty::with_units; + namespace u = xo::qty::u; using xo::qty::quantity; - using xo::flatstring; - constexpr quantity t = q::minutes(2); - constexpr quantity d = q::kilometers(2.5); + constexpr quantity t = q::minutes(2); + constexpr quantity d = q::kilometers(2.5); constexpr auto t2 = t*t; constexpr auto a = d / (t*t); @@ -174,8 +191,8 @@ with output: Remarks: - Assignment to ``t`` converted to representation ``double``. - We could have used :code:`quantity` to preserve - right-hand-side representation. + We could have instead used :code:`quantity` to propagate + right-hand-side representation Scale conversion and arithmetic ------------------------------- @@ -185,6 +202,8 @@ xo-unit uses at most one scale for each :term:`basis dimension` associated with When an arithmetic operator encounters basis units involving two different scales, the operator will adopt the scale provided by the left-hand argument: +See ``xo-unit/example/ex4`` for code below + .. code-block:: cpp :linenos: :emphasize-lines: 11 @@ -193,15 +212,13 @@ the operator will adopt the scale provided by the left-hand argument: #include int main() { - namespace u = xo::unit; - namespace qty = xo::units::qty; - using namespace std; + namespace q = xo::qty::qty; auto t1 = qty::milliseconds(1); auto t2 = qty::minutes(1); auto p = t1 * t2; - cerr << "t1: " << t1 << ", t2: " << t2 << ", p: " << p << endl; + std::cerr << "t1: " << t1 << ", t2: " << t2 << ", p: " << p << std::endl; } with output: @@ -210,9 +227,12 @@ with output: t1: 1ms, t2: 1min, t1*t2: 60000ms^2 + Dimensionless quantities unwrap implicitly ------------------------------------------ +Conversely, compiler rejects attempt to implictly unwrap a dimensioned quantity. + See ``xo-unit/examples/ex4`` for code below. .. code-block:: cpp @@ -237,13 +257,10 @@ See ``xo-unit/examples/ex4`` for code below. static_assert(std::same_as(r1), double>); - // static_assert fails b/c static_cast only available for dimensionless quantity - //static_assert(std::same_as(t2)), double>); - // r1_value: assignment compiles, since r1 dimensionless double r1_value = r1; - // r2_value: assignment won't compile, 'cannot convert' error + // r2_value: bad assignment won't compile, 'cannot convert' error //double r2_value = t2; std::cerr << "t1: " << t1 << ", t2: " << t2 << ", t1/t2: " << r1_value << std::endl; @@ -273,18 +290,19 @@ See ``xo-unit/examples/ex6`` for code below :emphasize-lines: 15 #include "xo/unit/quantity.hpp" + #include "xo/unit/quantity_iostream.hpp" #include int main () { namespace u = xo::unit::units; - namespace qty = xo::unit::qty; + namespace q = xo::unit::qty; using namespace std; /* 20% volatility over 250 days (approx number of trading days in one year) */ - auto q1 = qty::volatility250d(0.2); + auto q1 = q::volatility_250d(0.2); /* 10% volatility over 30 days */ - auto q2 = qty::volatility30d(0.1); + auto q2 = q::volatility_30d(0.1); auto sum = q1 + q2; auto prod = q1 * q2; @@ -306,3 +324,43 @@ with output: q2: 0.1mo^(-1/2) q1+q2: 0.54641yr360^(-1/2) q1*q2: 0.069282yr360^-1 + + +Dynamic dimension +----------------- + +If the dimension (or units) associated with a quantity are not known at compile-time, +use ``xo::qty::xquantity`` instead of ``xo::qty::quantity``. + +See ``xo-unit/example/ex8`` for code below + +.. code-block:: cpp + :linenos: + :emphasize-lines: 10-12 + + #include "xo/unit/xquantity.hpp" + #include "xo/unit/xquantity_iostream.hpp" + #include + + int + main () { + using namespace xo::qty; + namespace u = xo::qty::u; + + xquantity qty1(7, u::foot); + xquantity qty2(6.0, u::inch); + xquantity qty3 = qty1 + qty2; + + std::cerr << "qty1: " << qty1 << std::endl; + std::cerr << "qty2: " << qty2 << std::endl; + std::cerr << "qty3: " << qty3 << std::endl; + + /* rescale to mm */ + xquantity res = qty3.rescale(xo::qty::nu::millimeter); + + /* 2286mm */ + std::cerr << "res: " << res << std::endl; + } + +Here ``u::foot`` and ``u::inch`` are literals, +but they could have been read from console input or another runtime-only context. diff --git a/docs/implementation.rst b/docs/implementation.rst index 4f2802fc..54a7efdc 100644 --- a/docs/implementation.rst +++ b/docs/implementation.rst @@ -1,9 +1,23 @@ .. _implementation: -Abstraction Tower -================= +Components +========== -Abstraction tower for *xo-unit* components. +Library dependencies for *xo-unit*: + +.. ditaa:: + + +-----------------+ + | xo_unit | + +-----------------+ + | xo_ratio | + +-----------------+ + | xo_flatstring | + +-----------------+ + +``xo-unit`` also depends on ``xo-cmake`` macros. + +Abstraction tower for *xo-unit* components: .. ditaa:: @@ -25,14 +39,32 @@ Abstraction tower for *xo-unit* components. - :doc:`quantity`: - A quantity with compile-time unit work + A quantity with unit checking and conversion done at compile-time -- xquantity: + .. code-block:: cpp + + #include "xo/unit/quantity.hpp" + auto q1 = xo::qty::qty::kilometers(7.5); + +- :doc:`xquantity`: + + A quantity with unit checking and conversion done at run-time. + This is useful if unit information isn't known at compile time, for example + if reading units from console input. + + .. code-block:: cpp + + #include "xo/unit/xquantity.hpp" + xquantity qty1(7.5, xo::qty::u::foot) - A quantity with unit work deferred until runtime - :doc:`scaled_unit`: + .. code-block:: cpp + + #include "xo/unit/scaled_unit.hpp" + auto u = xo::qty::u::millimeter; + A unit involving zero or more dimensions, and associated conversion factor. - can express result of arithmetic involving multiple scales, @@ -45,6 +77,11 @@ Abstraction tower for *xo-unit* components. - :doc:`natural_unit` + .. code-block:: cpp + + #include "xo/unit/natural_unit.hpp" + auto u = xo::qty::nu::millimeter; + A unit involving zero or more dimensions, and at most one scale per dimension. A quantity instance is always represented as a dimensionless multiple of a natural unit @@ -56,24 +93,46 @@ Abstraction tower for *xo-unit* components. A rational (usually integer) power of a basis unit. Has a single dimension. + .. code-block:: cpp + + #include "xo/unit/bpu.hpp" + xo::qty::bpu(xo::qty::detail::bu::millimeter, + xo::qty::power_ratio_type(2)); // mm^2 + - :doc:`bu_store` Associates basis units with abbreviations. + Abbreviations used to decorate printed quantities. For example ``bu::kilogram`` => ``"kg"`` + .. code-block:: cpp + + #include "xo/unit/bu_store.hpp" + xo::qty::bu_abbrev_store.bu_abbrev(xo::qty::detail::bu::picogram); // "pg" + - :doc:`basis_unit` A unit with a single dimension and scale. + .. code-block:: cpp + + #include "xo/unit/basis_unit.hpp" + auto b = xo::qty::detail::bu::picogram; + - :doc:`dimension` identifies a dimension, such as mass or time. + .. code-block:: cpp + + #include "xo/unit/dimension.hpp" + auto d = xo::qty::dimension::mass; + Representation ============== -Worked example using :cpp:class:`xo::qty::quantity` +Worked example using :cpp:class:`xo::qty::quantity`. .. code-block:: cpp :linenos: @@ -81,11 +140,14 @@ Worked example using :cpp:class:`xo::qty::quantity` #include "xo/unit/quantity.hpp" ... + using xo::qty; namespace q = xo::qty::qty; // 7.55km.min^-2 quantity qty1 = 7.55 * q::kilometer / (q::minute * q::minute); +Note: in diagrams below, components with pale blue background are discarded before runtime + .. uml:: :caption: representation for quantity 7.55km.min^-2 :scale: 99% @@ -94,7 +156,7 @@ Worked example using :cpp:class:`xo::qty::quantity` object qty1<> qty1 : scale = 7.55 - rectangle { + rectangle #e0f0ff { object km_per_min2<> km_per_min2 : n_bpu = 2 @@ -132,7 +194,7 @@ Worked example using :cpp:class:`xo::qty::quantity` object qty2<> qty2 : scale = 123 - rectangle { + rectangle #e0f0ff { object ng_unit<> ng_unit : n_bpu = 1 @@ -163,7 +225,7 @@ Worked example using :cpp:class:`xo::qty::quantity` object qty3<> qty3 : scale = 928.65 - rectangle { + rectangle #e0f0ff { object ng_km_min2_unit<> ng_km_min2_unit : n_bpu = 3 @@ -214,7 +276,7 @@ Worked example using :cpp:class:`xo::qty::quantity` object qty3b<> qty3b : scale = 2.59758e-10 - rectangle { + rectangle #e0f0ff { object kg_m_s2_unit<> kg_m_s2_unit : n_bpu = 3 diff --git a/docs/index.rst b/docs/index.rst index ccba32b7..87c3b9f2 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -33,15 +33,15 @@ runtime (since we can't construct new c++ types at runtime). install examples implementation - development - unit-quantities quantity-reference - scaled-unit-class + xquantity-reference + scaled-unit-reference natural-unit-class bpu-class bu-store-class basis-unit-reference dimension-enum + development Indices and Tables ------------------ diff --git a/docs/install.rst b/docs/install.rst index 2ff7ad8c..7000af9a 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -6,24 +6,39 @@ Install ======= -`xo-unit source`_ lives on github. +``xo-unit`` uses supporting header-only libraries ``xo-ratio`` and ``xo-flatstring``. +All three are on github: + +- `xo-unit source`_ +- `xo-ratio source`_ +- `xo-flatstring source`_ .. _xo-unit source: https://github.com/rconybea/xo-unit +.. _xo-ratio source: https://github.com/rconybea/xo-ratio +.. _xo-flatstring source: https://github.com/rconybea/xo-flatstring Implementation relies on some c++20 features (for example class-instances as template arguments). Tested with gcc 12.3, 13.2 +``xo-unit`` also relies on sister header-only libraries: + +One way to use ``xo-unit`` in a project is to import the source tree directly: + Include as submodule -------------------- .. code-block:: bash cd myproject + git submodule add -b main https://github.com/rconybea/xo-flatstring ext/xo-flatstring + git submodule add -b main https://github.com/rconybea/xo-ratio ext/xo-ratio git submodule add -b main https://github.com/rconybea/xo-unit ext/xo-unit git submodule update --init This assumes you organize directly-incorporated dependencies under directory ``myproject/ext``. -You would then add ``myproject/ext/xo-unit/include`` to your compiler's include path, +You would then add to your compiler's include path the directories ``myproject/ext/xo-flatstring/include``, +``myproject/ext/xo-ratio/include``, ``myproject/ext/xo-unit/include``; + and add .. code-block:: c++ @@ -32,31 +47,258 @@ and add to c++ source files that rely on xo-unit +Ubuntu Install Pattern +---------------------- + +Example instructions (from github actions CI) for build starting from stock ubuntu are in `ubuntu-main.yml`_ + +.. _ubuntu-main.yml: https://github.com/Rconybea/xo-unit/blob/main/.github/workflows/ubuntu-main.yml + + +Installing from source +---------------------- + +Although the xo-unit, xo-ratio and xo-flatstring libraries are header-only, +they do have a build dependency on shared cmake macros, and a bootstrap script `xo-cmake-config`. + +* `xo-cmake`_ source + +.. _xo-cmake: https://github.com/rconybea/xo-cmake + +Preamble: + +.. code-block:: bash + + mkdir -p ~/proj/xo + cd ~/proj/xo + + git clone https://github.com/rconybea/xo-cmake + git clone https://github.com/rconybea/xo-flatstring + git clone https://github.com/rconybea/xo-ratio + git clone https://github.com/rconybea/xo-unit + + PREFIX=~/local # ..or other desired installation prefix + +Ordering below is important; cmake support for each subsystem +requires successful installation of its predecessor. + +Install `xo-cmake`: + +.. code-block:: bash + + cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -B xo-cmake/.build -S xo-cmake + cmake --build xo-cmake/.build -j # placeholder, no-op for now + cmake --install xo-cmake/.build + +Build and Install `xo-flatstring`: + +.. code-block:: bash + + cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -DENABLE_TESTING=0 \ + -B xo-flatstring/.build -S xo-flatstring + cmake --build xo-flatstring/.build -j + cmake --install xo-flatstring/.build + +Build and Install `xo-ratio`: + +.. code-block:: bash + + cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -DENABLE_TESTING=0 \ + -B xo-ratio/.build -S xo-ratio + cmake --build xo-ratio/.build -j + cmake --install xo-ratio/.build + +Build and Install `xo-unit`: + +.. code-block:: bash + + cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -DENABLE_TESTING=0 \ + -B xo-unit/.build -S xo-unit + cmake --build xo-unit/.build -j + cmake --install xo-unit/.build + +Directories under ``PREFIX`` will then contain: + +.. code-block:: + + PREFIX + +- bin + | \- xo-cmake-config + +- include + | \- xo + | +- cxxutil/ + | +- flatstring/ + | +- ratio/ + | +- unit/ + +- lib + | \- cmake + | +- indentlog/ + | +- randomgen/ + | +- xo_flatstring/ + | \- xo_unit/ + +- share + \- cmake + \- xo_macros/ + +Use CMake Support +----------------- + +To use built-in cmake suport: + +Make sure ``PREFIX/lib/cmake`` is searched by cmake (if necessary, include it in ``CMAKE_PREFIX_PATH``) + +Add to ``CMakeLists.txt``: + +.. code-block:: cmake + + FindPackage(xo_unit CONFIG REQUIRED) + + target_link_libraries(mytarget INTERFACE xo_unit) + +Build and Install with Unit Tests Enabled +----------------------------------------- + +Running unit tests require a few additional dependencies: + +* `catch2`_ header-only unit-test framework +* `xo-indentlog`_ logging with call-structure indenting +* `xo-randomgen`_ fast random number generator (xoshiro256ss) + +.. _catch2: https://github.com/catchorg/Catch2 +.. _xo-indentlog: https://github.com/rconybea/indentlog +.. _xo-randomgen: https://github.com/rconybea/randomgen + +Preamble: + +.. code-block:: bash + + mkdir -p ~/proj/xo + cd ~/proj/xo + + git clone https://github.com/rconybea/xo-cmake + git clone https://github.com/rconybea/indentlog xo-indentlog + git clone https://github.com/rconybea/randomgen xo-randomgen + git clone https://github.com/rconybea/xo-flatstring + git clone https://github.com/rconybea/xo-ratio + git clone https://github.com/rconybea/xo-unit + + PREFIX=~/local # ..or other desired installation prefix + +Build and Install `catch2` (assuming ubuntu here): + +.. code-block:: bash + + sudo apt-get install catch2 # on ubuntu, for example + +Build and Install `xo-cmake`: + +.. code-block:: bash + + cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -B xo-cmake/.build -S xo-cmake + cmake --build xo-cmake/.build -j # placeholder, no-op for now + cmake --install xo-cmake/.build + +Build, Test and Install `xo-indentlog`: + +.. code-block:: bash + + cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -B xo-indentlog/.build -S xo-indentlog + cmake --build xo-indentlog/.build -j + cmake --build xo-indentlog/.build -- test # run unit tests, cmake invokes ctest + (cd xo-indentlog/.build && ctest) # or invoke ctest directly + cmake --install xo-indentlog/.build + +Build and Install `xo-randomgen` (no unit tests yet): + +.. code-block:: bash + + cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -B xo-randomgen/.build -S xo-randomgen + cmake --build xo-randomgen/.build -j + cmake --install xo-randomgen/.build + +Build, Test and Install `xo-flatstring`: + +.. code-block:: bash + + cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -B xo-flatstring/.build -S xo-flatstring + cmake --build xo-flatstring/.build -j + cmake --build xo-flatstring/.build -- test # run unit tests, cmake invokes ctest + (cd xo-flatstring/.build && ctest) # or invoke ctest directly + cmake --install xo-flatstring/.build + +Build, Test and Install `xo-ratio`: + +.. code-block:: bash + + cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -B xo-ratio/.build -S xo-ratio + cmake --build xo-ratio/.build -j + cmake --build xo-ratio/.build -- test # run unit tests, cmake invokes ctest + (cd xo-ratio/.build && ctest) # or invoke ctest directly + cmake --install xo-ratio/.build + +Build, Test and Install `xo-unit`: + +.. code-block:: bash + + cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -B xo-unit/.build -S xo-unit + cmake --build xo-unit/.build -j + cmake --build xo-unit/.build -- test # run unit tests, cmake invokes ctest + (cd xo-unit/.build && ctest) # or invoke ctest directly + cmake --install xo-unit/.build + +Build Examples +-------------- + +To enable building example programs: + +.. code-block:: bash + + cd ~/proj/xo + cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -DXO_ENABLE_EXAMPLES=1 -B xo-unit/.build -S xo-unit + +Run examples from the build directory: + +.. code-block:: bash + + ~/proj/xo/xo-unit/.build/example/ex1/xo_unit_ex1 + ~/proj/xo/xo-unit/.build/example/ex2/xo_unit_ex2 + # etc + +Build and Install Documentation +------------------------------- + +xo-unit documentation has these additional dependencies: + +* `doxygen`_ annotation-driven inline documentation +* `sphinx`_ documentation based on ReST files +* `sphinx-rtd-theme`_ popular CSS theme for sphinx +* `breathe`_ make doxygen-generated ingredients available from sphinx + +.. _doxygen: https://www.doxygen.nl +.. _sphinx: https://www.sphinx-doc.org +.. _sphinx-rtd-theme: https://pypi.org/project/sphinx-rtd-theme +.. _breathe: https://breathe.readthedocs.io/en/latest + +Preamble (assuming ubuntu here): + +.. code-block:: bash + + sudo apt-get install doxygen + sudo apt-get install python3-sphinx + sudo apt-get install python3-sphinx-rtd-theme + sudo apt-get install python3-breathe + +Build `xo-unit` docs + +.. code-block:: bash + + cd ~/proj/xo + cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -B xo-unit/.build + cmake --build xo-unit/.build -- docs + cmake --install xo-unit/.build # if docs built, installs to $PREFIX/share/doc/xo_unit/html + Supported compilers ------------------- * developed with gcc 12.3.0 and gcc 13.2.0; github CI using gcc 11.4.0 (asof March 2024) -Building from source --------------------- - -Although the xo-unit library is header-only, unit tests have some dependencies. -Example instructions (github CI) for build starting from stock ubuntu are in `ubuntu-main.yml`_ - -.. _ubuntu-main.yml: https://github.com/Rconybea/xo-unit/blob/main/.github/workflows/ubuntu-main.yml - -Unit test dependencies: - -* `catch2`_ header-only unit-test framework -* `xo-cmake`_ cmake macros -* `xo-indentlog`_ logging with call-structure indenting -* `xo-refcnt`_ intrusive reference counting (needed by xo-reflect) -* `xo-subsys`_ plugin initialization support (needed by xo-reflect) -* `xo-reflect`_ c++ introspection library - -.. _catch2: https://github.com/catchorg/Catch2 -.. _xo-cmake: https://github.com/rconybea/xo-cmake -.. _xo-indentlog: https://github.com/rconybea/indentlog -.. _xo-refcnt: https://github.com/rconybea/refcnt -.. _xo-subsys: https://github.com/rconybea/subsys -.. _xo-reflect: https://github.com/rconybea/reflect diff --git a/docs/natural-unit-class.rst b/docs/natural-unit-class.rst index 4a4db38c..b7eea47d 100644 --- a/docs/natural-unit-class.rst +++ b/docs/natural-unit-class.rst @@ -3,38 +3,107 @@ Natural Unit ============ -.. ditaa:: +A natural unit represents a product of terms, each involving a distinct basis dimension - +----------------+----------------+ - | quantity | xquantity | - +----------------+----------------+ - | scaled_unit | - +---------------------------------+ - |cYEL natural_unit | - +---------------------------------+ - | bpu | - +----------------+ | - | bu_store | | - +----------------+----------------+ - | basis_unit | - +---------------------------------+ - | dimension | - +---------------------------------+ +Context +------- + +.. ditaa:: + :--scale: 0.85 + + +----------------+---------------+ + | quantity | xquantity | + +----------------+---------------+ + | scaled_unit | + +--------------------------------+ + |cYEL natural_unit | + +--------------------------------+ + | bpu | + +----------------+ | + | bu_store | | + +----------------+---------------+ + | basis_unit | + +--------------------------------+ + | dimension | + +--------------------------------+ + +Introduction +------------ .. code-block:: cpp #include -Representation for the unit associated with a @ref quantity or xquantity. +Representation for the unit associated with a :doc:`xquantity` - represents a cartesian product of basis units. - constexpr implementation - limited support for fractional dimensions such as time^-1/2 +.. uml:: + :caption: natural unit for a Newton (unit of force) + :scale: 99% + :align: center + + object newton<> + newton : n_bpu = 3 + newton : bpu_v[] + + object kg<> + kg : native_dim = dim::mass + kg : scalefactor = 1000/1 + kg : power = 1/1 + + object m<> + m : native_dim = dim::distance + m : scalefactor = 1/1 + m : power = 1/1 + + object s2<> + s2 : native_dim = dim::time + s2 : scalefactor = 1/1 + s2 : power = -2/1 + + newton o-- kg + newton o-- m + newton o-- s2 + +Class +----- + .. doxygenclass:: xo::qty::natural_unit +Member Variables +---------------- + .. doxygengroup:: natural-unit-instance-vars + +Type Traits +----------- + +.. doxygengroup:: natural-unit-type-traits + +Constructors +------------ + .. doxygengroup:: natural-unit-ctors + +Access Methods +-------------- + .. doxygengroup:: natural-unit-access-methods + +General Methods +--------------- + .. doxygengroup:: natural-unit-methods + +Conversion +---------- + .. doxygengroup:: natural-unit-conversion-methods + +Comparison Functions +-------------------- + +.. doxygengroup:: natural-unit-comparison-functions diff --git a/docs/quantity-class.rst b/docs/quantity-class.rst index e26469e7..7e74abb5 100644 --- a/docs/quantity-class.rst +++ b/docs/quantity-class.rst @@ -3,26 +3,70 @@ Quantity ======== +.. ditaa:: + + +----------------+---------------+ + |cYEL quantity | xquantity | + +----------------+---------------+ + | scaled_unit | + +--------------------------------+ + | natural_unit | + +--------------------------------+ + | bpu | + +----------------+ | + | bu_store | | + +----------------+---------------+ + | basis_unit | + +--------------------------------+ + | dimension | + +--------------------------------+ + .. code-block:: cpp #include +.. uml:: + :scale: 99% + :align: center + + allowmixing + + object qty1<> + qty1 : scale = 1.23 + + rectangle constexpr #e0f0ff { + + object unit<> + + qty1 o-- unit : s_unit (static constexpr) + + } + +Arithmetic on :doc:`xo::qty::quantity` instances +does *not* use ``xo::qty::quantity::s_scaled_unit`` at runtime; +instead gets everything it needs at compile time. + +Class +----- + The primary data structure for interacting with xo-unit is the template class ``xo::qty::quantity``. +A quantity is a compile-time wrapper around a single arithmetic value, +with type taken from the ``Repr`` parameter in ``quantity``. .. doxygenclass:: xo::qty::quantity -Type Traits ------------ - -.. doxygengroup:: quantity-type-traits - Member Variables ---------------- .. doxygengroup:: quantity-static-vars .. doxygengroup:: quantity-instance-vars +Type Traits +----------- + +.. doxygengroup:: quantity-type-traits + Constructors ------------ diff --git a/docs/quantity-factoryfunctions.rst b/docs/quantity-factoryfunctions.rst index daf4e8ea..3f68c3c5 100644 --- a/docs/quantity-factoryfunctions.rst +++ b/docs/quantity-factoryfunctions.rst @@ -1,5 +1,23 @@ .. _quantity_factoryfunctions: +.. ditaa:: + + +----------------+---------------+ + |cYEL quantity | xquantity | + +----------------+---------------+ + | scaled_unit | + +--------------------------------+ + | natural_unit | + +--------------------------------+ + | bpu | + +----------------+ | + | bu_store | | + +----------------+---------------+ + | basis_unit | + +--------------------------------+ + | dimension | + +--------------------------------+ + .. toctree:: :maxdepth: 2 @@ -12,20 +30,39 @@ Quantity Factory Functions Mass ---- +.. doxygenfunction:: xo::qty::qty::picograms +.. doxygenfunction:: xo::qty::qty::nanograms +.. doxygenfunction:: xo::qty::qty::micrograms .. doxygenfunction:: xo::qty::qty::milligrams .. doxygenfunction:: xo::qty::qty::grams .. doxygenfunction:: xo::qty::qty::kilograms +.. doxygenfunction:: xo::qty::qty::tonnes +.. doxygenfunction:: xo::qty::qty::kilotonnes +.. doxygenfunction:: xo::qty::qty::megatonnes +.. doxygenfunction:: xo::qty::qty::gigatonnes Distance -------- +.. doxygenfunction:: xo::qty::qty::picometers +.. doxygenfunction:: xo::qty::qty::nanometers +.. doxygenfunction:: xo::qty::qty::micrometers .. doxygenfunction:: xo::qty::qty::millimeters .. doxygenfunction:: xo::qty::qty::meters .. doxygenfunction:: xo::qty::qty::kilometers +.. doxygenfunction:: xo::qty::qty::megameters +.. doxygenfunction:: xo::qty::qty::gigameters + +.. doxygenfunction:: xo::qty::qty::lightseconds +.. doxygenfunction:: xo::qty::qty::astronomicalunits .. doxygenfunction:: xo::qty::qty::inches +.. doxygenfunction:: xo::qty::qty::feet +.. doxygenfunction:: xo::qty::qty::yards +.. doxygenfunction:: xo::qty::qty::miles Time ---- +.. doxygenfunction:: xo::qty::qty::picoseconds .. doxygenfunction:: xo::qty::qty::nanoseconds .. doxygenfunction:: xo::qty::qty::microseconds .. doxygenfunction:: xo::qty::qty::milliseconds @@ -33,3 +70,16 @@ Time .. doxygenfunction:: xo::qty::qty::minutes .. doxygenfunction:: xo::qty::qty::hours .. doxygenfunction:: xo::qty::qty::days +.. doxygenfunction:: xo::qty::qty::weeks +.. doxygenfunction:: xo::qty::qty::months +.. doxygenfunction:: xo::qty::qty::years +.. doxygenfunction:: xo::qty::qty::year250s +.. doxygenfunction:: xo::qty::qty::year360s +.. doxygenfunction:: xo::qty::qty::year365s + +Volatility +---------- +.. doxygenfunction:: xo::qty::qty::volatility_30d +.. doxygenfunction:: xo::qty::qty::volatility_250d +.. doxygenfunction:: xo::qty::qty::volatility_360d +.. doxygenfunction:: xo::qty::qty::volatility_365d diff --git a/docs/scaled-unit-class.rst b/docs/scaled-unit-class.rst index 40788203..7193eddf 100644 --- a/docs/scaled-unit-class.rst +++ b/docs/scaled-unit-class.rst @@ -3,7 +3,13 @@ Scaled Unit =========== +A dimensionless multiple of a :doc:`natural_unit` + +Context +------- + .. ditaa:: + :--scale: 0.85 +----------------+----------------+ | quantity | xquantity | @@ -21,15 +27,53 @@ Scaled Unit | dimension | +---------------------------------+ +Introduction +------------ .. code-block::cpp #include -Result of mutliplication or division of natural units (:doc:`natural-unit-class`). +Extension of :doc:`natural_unit` to enable representing the intermediate +result of multiplication (or division) of natural units. + +- represents a (dimensionless) multiple of a cartesian product of basis units. +- constexpr implementation +- limited support for fractional dimensions such as time^-1/2 + +.. uml:: + :caption: scaled unit after (u::meter * u::foot / u::minute) + :scale: 99% + :align: center + + object area_per_time<> + area_per_time : outer_scale_factor = 3048/10000 + area_per_time : outer_scale_sq = 1.0 + area_per_time : natural_unit = m2_per_min + + object m2_per_min<> + m2_per_min : n_bpu = 2 + m2_per_min : bpu_v[] + + object m2<> + m2 : native_dim = dim::distance + m2 : scalefactor = 1/1 + m2 : power = 2/1 + + object min<> + min : native_dim = dim::time + min : scalefactor = 60/1 + min : power = -1/1 + + area_per_time o-- m2_per_min + m2_per_min o-- m2 + m2_per_min o-- min + +Scaled units with non-unity outer scalefactors arise as intermediate results +of quantity arithmetic Motivation ----------- +^^^^^^^^^^ Consider multiplying two units: @@ -47,13 +91,75 @@ to do this we accumulate a product of conversion factors from such consolidation For example: .. code-block:: cpp + :emphasize-lines: 3 - static_assert(u_prod.natural_unit[0].bu() == detail::bu::meter); - static_assert(u_prod.natural_unit[0].power() == power_ratio_type(2)); + static_assert(u_prod.n_bpu() == 1); + static_assert(u_prod[0].bu() == detail::bu::meter); + static_assert(u_prod[0].power() == power_ratio_type(2)); static_assert(u_prod.outer_scale_factor_ == xo::ratio::ratio(1000)); static_assert(u_prod.outer_scale_sq_ == 1.0); // used if fractional dimension +Here we accumulate :code:`1000`, from converting kilometers to meters. + +Division works similarly. In this example dimension cancel, but we still have a non-unity conversion factor. + +.. code-block:: cpp + :emphasize-lines: 7 + + namespace u = xo::qty::u; + + constexpr auto u_div = u::meter / u::kilometer; + + // dimensionlesss result + static_assert(u_prod.n_bpu() == 0); + static_assert(u_prod.outer_scale_factor_ == xo::ratio::ratio(1,1000)); + static_assert(u_prod.outer_scale_sq_ == 1.0); + +When multiple dimensions needing conversion are involved, scalefactors accumulate: + +.. code-block:: cpp + :emphasize-lines: 8 + + namespace u = xo::qty::u; + + constexpr auto u2_prod = u::meter * u::hour * u::kilometer * u::minute; + + static_assert(u2_prod.n_bpu() == 2); + static_assert(u2_prod[0].bu() == detail::bu::meter); + static_assert(u2_prod[1].bu() == detail::bu::hour); + static_assert(u2_prod.outer_scale_factor_ == xo::ratio::ratio(50,3)); + static_assert(u2_prod.outer_scale_sq_ == 1.0); // used if fractional dimension + +Here the :code:`50/3` result comes from multiplying :code:`1000/1` (converting kilometers -> meters) +by :code:`1/60` (converting minutes -> hours) + + Class ----- .. doxygenclass:: xo::qty::scaled_unit + +Member Variables +---------------- + +.. doxygengroup:: scaled-unit-instance-vars + +Type Traits +----------- + +.. doxygengroup:: scaled-unit-type-traits + +Access Methods +-------------- + +.. doxygengroup:: scaled-unit-access-methods + +General Methods +--------------- + +.. doxygengroup:: scaled-unit-general-methods + +Operators +--------- + +.. doxygengroup:: scaled-unit-operators diff --git a/docs/scaled-unit-constants.rst b/docs/scaled-unit-constants.rst new file mode 100644 index 00000000..46757c02 --- /dev/null +++ b/docs/scaled-unit-constants.rst @@ -0,0 +1,75 @@ +.. _scaled-unit-constants + +Scaled Unit Constants +===================== + +Built-in unit constants. + +Context +------- + +.. ditaa:: + :--scale: 0.85 + + +----------------+---------------+ + | quantity | xquantity | + +----------------+---------------+ + |cYEL scaled_unit | + +--------------------------------+ + | natural_unit | + +--------------------------------+ + | bpu | + +----------------+ | + | bu_store | | + +----------------+---------------+ + | basis_unit | + +--------------------------------+ + | dimension | + +--------------------------------+ + +Introduction +------------ + +Built-in units. Application code may use these to trigger conversion + +.. code-block:: cpp + :emphasize-lines: 5 + + #include + + using namespace xo::qty; + + constexpr quantity q1 = q::miles(60) / q::hour; + +Note that it's often easiest to use :doc:`unit quantity constants`, +like :code:`q::hour` in the example above + +Dimensionless Constant +---------------------- + +.. doxygengroup:: scaled-unit-dimensionless + +Mass Units +---------- + +.. doxygengroup:: scaled-unit-mass + +Distance Units +-------------- + +.. doxygengroup:: scaled-unit-distance + +Time Units +---------- + +.. doxygengroup:: scaled-unit-time + +Volatility Units +---------------- + +.. doxygengroup:: scaled-unit-volatility + +Miscellaneous Units +------------------- + +.. doxygengroup:: scaled-unit-misc diff --git a/docs/scaled-unit-reference.rst b/docs/scaled-unit-reference.rst new file mode 100644 index 00000000..61ec0dee --- /dev/null +++ b/docs/scaled-unit-reference.rst @@ -0,0 +1,31 @@ +.. _scaled-unit-reference: + +Scaled Unit Reference +===================== + +A dimensionless multiple of a :doc:`natural_unit` + +.. ditaa:: + :--scale: 0.85 + + +----------------+---------------+ + | quantity | xquantity | + +----------------+---------------+ + |cYEL scaled_unit | + +--------------------------------+ + | natural_unit | + +--------------------------------+ + | bpu | + +----------------+ | + | bu_store | | + +----------------+---------------+ + | basis_unit | + +--------------------------------+ + | dimension | + +--------------------------------+ + +.. toctree:: + :maxdepth: 1 + + Scaled Unit Class + scaled-unit-constants diff --git a/docs/unit-concept.rst b/docs/unit-concept.rst deleted file mode 100644 index 387289d8..00000000 --- a/docs/unit-concept.rst +++ /dev/null @@ -1,12 +0,0 @@ -.. _unit-concept: - -Unit Concepts -============= - -.. code-block:: cpp - - #include - -.. doxygenconcept:: xo::unit::unit_concept - -.. doxygenconcept:: xo::unit::basis_unit_concept diff --git a/docs/unit-quantities.rst b/docs/unit-quantities.rst deleted file mode 100644 index 30e57de6..00000000 --- a/docs/unit-quantities.rst +++ /dev/null @@ -1,93 +0,0 @@ -.. _unit-quantities: - -.. toctree - :maxdepth: 2 - -Unit Quantities -=============== - -Xo-unit uses the type system to represent units. -This is great for eliminating runtime overhead. - -One place where we face some awkwardness is conversions involving multiple dimensions. -We'd like to write something concise like - -.. code-block:: cpp - - meter / (second * second); - -The difficulty arises because xo-unit represents `meter` and `second` by types -(``xo::unit::units::meter`` and ``xo::unit::units::second``); operators like `*` and `/` -apply to *values*, not types. - -We'll present various ways to express rescaling below - -Converting units ----------------- - -First, xo-unit provides constexpr unit quantities in namespace ``xo::unit::unit_qty``: - -.. code-block:: cpp - :linenos: - - static constexpr auto meter = qty::meters(1); - static constexpr auto kilometer = qty::kilometers(1); - // etc - -Second, a method ``quantity::with_units_from`` that takes units (only) from its argument: -``quantity::with_units_from`` just extracts its argument's unit_type to call ``quantity::with_units``. - -.. code-block:: cpp - :linenos: - - template - template - auto quantity::with_units_from(Quantity q) { - return this->with_units(); - } - -Motivation is that it's easier to express an argument to `with_units_from` -than to express template arguments to `with_units`. - -Prefer - -.. code-block:: cpp - :linenos: - :emphasize-lines: 5 - - namespace u = xo::unit::unit_qty; // u::meter is a value - namespace qty = xo::unit::qty; - - auto q1 = qty::kilometers(150.0) / qty::hours(0.5); - auto q2 = q1.with_units_from(u::meter / u::second); - -instead of the more verbose: - -.. code-block:: cpp - :linenos: - :emphasize-lines: 5-6 - - namespace u = xo::unit::units; // u::meter is a type - - auto q1 = qty::kilometers(150.0) / qty::hours(0.5); - - auto q2 = q1.with_units>>(); - -Using basis units ------------------ - -An alternative way to request multidimensional unit conversion is with basis units - -.. code-block:: cpp - :linenos: - :emphasize-lines: 4-5 - - namespace u = xo::unit::units; // u::meter is a type - - auto q1 = qty::kilometers(150.0) / qty::hours(0.5); - auto q2 = q1.with_basis_unit(); // q2 in km.s^-1 - auto q3 = q2.with_basis_unit(); // q3 in m.s^-1 - -With this technique we don't have to supply the basis dimension's exponent. -Instead we're just giving scale. diff --git a/docs/unit-reference.rst b/docs/unit-reference.rst deleted file mode 100644 index a329f486..00000000 --- a/docs/unit-reference.rst +++ /dev/null @@ -1,10 +0,0 @@ -.. _unit-reference: - -Unit Reference -============== - -.. toctree:: - :maxdepth: 2 - :caption: Unit Reference - - unit-concept diff --git a/docs/xquantity-class.rst b/docs/xquantity-class.rst new file mode 100644 index 00000000..dba2ca58 --- /dev/null +++ b/docs/xquantity-class.rst @@ -0,0 +1,15 @@ +.. _xquantity-class: + +Xquantity +========= + +.. code-block:: cpp + + #include + +Class +----- + +Class with run-time unit representation. + +.. doxygenclass:: xo::qty::xquantity diff --git a/docs/xquantity-reference.rst b/docs/xquantity-reference.rst new file mode 100644 index 00000000..511f4db0 --- /dev/null +++ b/docs/xquantity-reference.rst @@ -0,0 +1,27 @@ +.. _xquantity-reference: + +Xquantity Reference +=================== + +.. ditaa:: + + +----------------+---------------+ + | quantity |cYEL xquantity | + +----------------+---------------+ + | scaled_unit | + +--------------------------------+ + | natural_unit | + +--------------------------------+ + | bpu | + +----------------+ | + | bu_store | | + +----------------+---------------+ + | basis_unit | + +--------------------------------+ + | dimension | + +--------------------------------+ + +.. toctree:: + :maxdepth: 2 + + xquantity-class diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index fc69f5c4..41c95a84 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -5,3 +5,5 @@ add_subdirectory(ex4) add_subdirectory(ex5) add_subdirectory(ex6) add_subdirectory(ex7) +add_subdirectory(ex8) +add_subdirectory(ex_su) diff --git a/example/ex1/CMakeLists.txt b/example/ex1/CMakeLists.txt index 2eb9064a..fb1b6879 100644 --- a/example/ex1/CMakeLists.txt +++ b/example/ex1/CMakeLists.txt @@ -3,12 +3,10 @@ set(SELF_EXE xo_unit_ex1) set(SELF_SRCS ex1.cpp) -xo_add_executable(${SELF_EXE} ${SELF_SRCS}) - -# ---------------------------------------------------------------- -# dependencies.. - -xo_self_headeronly_dependency(${SELF_EXE} xo_unit) -xo_dependency(${SELF_EXE} xo_flatstring) +if (XO_ENABLE_EXAMPLES) + xo_add_executable(${SELF_EXE} ${SELF_SRCS}) + xo_self_headeronly_dependency(${SELF_EXE} xo_unit) + xo_dependency(${SELF_EXE} xo_flatstring) +endif() # end CMakeLists.txt diff --git a/example/ex2/CMakeLists.txt b/example/ex2/CMakeLists.txt index bfc49c4b..82406fe6 100644 --- a/example/ex2/CMakeLists.txt +++ b/example/ex2/CMakeLists.txt @@ -3,12 +3,10 @@ set(SELF_EXE xo_unit_ex2) set(SELF_SRCS ex2.cpp) -xo_add_executable(${SELF_EXE} ${SELF_SRCS}) - -# ---------------------------------------------------------------- -# dependencies.. - -xo_self_headeronly_dependency(${SELF_EXE} xo_unit) -xo_dependency(${SELF_EXE} xo_flatstring) +if (XO_ENABLE_EXAMPLES) + xo_add_executable(${SELF_EXE} ${SELF_SRCS}) + xo_self_headeronly_dependency(${SELF_EXE} xo_unit) + xo_dependency(${SELF_EXE} xo_flatstring) +endif() # end CMakeLists.txt diff --git a/example/ex3/CMakeLists.txt b/example/ex3/CMakeLists.txt index aebfe0fe..06410943 100644 --- a/example/ex3/CMakeLists.txt +++ b/example/ex3/CMakeLists.txt @@ -3,12 +3,10 @@ set(SELF_EXE xo_unit_ex3) set(SELF_SRCS ex3.cpp) -xo_add_executable(${SELF_EXE} ${SELF_SRCS}) - -# ---------------------------------------------------------------- -# dependencies.. - -xo_self_headeronly_dependency(${SELF_EXE} xo_unit) -xo_dependency(${SELF_EXE} xo_flatstring) +if (XO_ENABLE_EXAMPLES) + xo_add_executable(${SELF_EXE} ${SELF_SRCS}) + xo_self_headeronly_dependency(${SELF_EXE} xo_unit) + xo_dependency(${SELF_EXE} xo_flatstring) +endif() # end CMakeLists.txt diff --git a/example/ex3/ex3.cpp b/example/ex3/ex3.cpp index 30754ffa..d63bb71d 100644 --- a/example/ex3/ex3.cpp +++ b/example/ex3/ex3.cpp @@ -8,9 +8,7 @@ int main () { namespace q = xo::qty::qty; namespace u = xo::qty::u; - //namespace nu = xo::qty::nu; using xo::qty::quantity; - using xo::flatstring; using namespace std; constexpr quantity t = q::minutes(2); diff --git a/example/ex4/CMakeLists.txt b/example/ex4/CMakeLists.txt index cfec5b2a..cb1ce76b 100644 --- a/example/ex4/CMakeLists.txt +++ b/example/ex4/CMakeLists.txt @@ -3,12 +3,10 @@ set(SELF_EXE xo_unit_ex4) set(SELF_SRCS ex4.cpp) -xo_add_executable(${SELF_EXE} ${SELF_SRCS}) - -# ---------------------------------------------------------------- -# dependencies.. - -xo_self_headeronly_dependency(${SELF_EXE} xo_unit) -xo_dependency(${SELF_EXE} xo_flatstring) +if (XO_ENABLE_EXAMPLES) + xo_add_executable(${SELF_EXE} ${SELF_SRCS}) + xo_self_headeronly_dependency(${SELF_EXE} xo_unit) + xo_dependency(${SELF_EXE} xo_flatstring) +endif() # end CMakeLists.txt diff --git a/example/ex4/ex4.cpp b/example/ex4/ex4.cpp index 573a6b92..6691bd7d 100644 --- a/example/ex4/ex4.cpp +++ b/example/ex4/ex4.cpp @@ -17,7 +17,6 @@ main () { static_assert(!t2.is_dimensionless()); static_assert(std::same_as(r1)), double>); - //static_assert(std::same_as(t2)), double>); /* r1_value: assignment compiles, since r1 dimensionless */ double r1_value = r1; diff --git a/example/ex5/CMakeLists.txt b/example/ex5/CMakeLists.txt index bd2e4253..3d59c0ff 100644 --- a/example/ex5/CMakeLists.txt +++ b/example/ex5/CMakeLists.txt @@ -3,12 +3,10 @@ set(SELF_EXE xo_unit_ex5) set(SELF_SRCS ex5.cpp) -xo_add_executable(${SELF_EXE} ${SELF_SRCS}) - -# ---------------------------------------------------------------- -# dependencies.. - -xo_self_headeronly_dependency(${SELF_EXE} xo_unit) -xo_dependency(${SELF_EXE} xo_flatstring) +if (XO_ENABLE_EXAMPLES) + xo_add_executable(${SELF_EXE} ${SELF_SRCS}) + xo_self_headeronly_dependency(${SELF_EXE} xo_unit) + xo_dependency(${SELF_EXE} xo_flatstring) +endif() # end CMakeLists.txt diff --git a/example/ex6/CMakeLists.txt b/example/ex6/CMakeLists.txt index ee836bc7..bbb62dd1 100644 --- a/example/ex6/CMakeLists.txt +++ b/example/ex6/CMakeLists.txt @@ -3,12 +3,10 @@ set(SELF_EXE xo_unit_ex6) set(SELF_SRCS ex6.cpp) -xo_add_executable(${SELF_EXE} ${SELF_SRCS}) - -# ---------------------------------------------------------------- -# dependencies.. - -xo_self_headeronly_dependency(${SELF_EXE} xo_unit) -xo_dependency(${SELF_EXE} xo_flatstring) +if (XO_ENABLE_EXAMPLES) + xo_add_executable(${SELF_EXE} ${SELF_SRCS}) + xo_self_headeronly_dependency(${SELF_EXE} xo_unit) + xo_dependency(${SELF_EXE} xo_flatstring) +endif() # end CMakeLists.txt diff --git a/example/ex7/CMakeLists.txt b/example/ex7/CMakeLists.txt index 33832b41..a13bc9f7 100644 --- a/example/ex7/CMakeLists.txt +++ b/example/ex7/CMakeLists.txt @@ -3,12 +3,10 @@ set(SELF_EXE xo_unit_ex7) set(SELF_SRCS ex7.cpp) -xo_add_executable(${SELF_EXE} ${SELF_SRCS}) - -# ---------------------------------------------------------------- -# dependencies.. - -xo_self_headeronly_dependency(${SELF_EXE} xo_unit) -xo_dependency(${SELF_EXE} xo_flatstring) +if (XO_ENABLE_EXAMPLES) + xo_add_executable(${SELF_EXE} ${SELF_SRCS}) + xo_self_headeronly_dependency(${SELF_EXE} xo_unit) + xo_dependency(${SELF_EXE} xo_flatstring) +endif() # end CMakeLists.txt diff --git a/example/ex8/CMakeLists.txt b/example/ex8/CMakeLists.txt new file mode 100644 index 00000000..42681a72 --- /dev/null +++ b/example/ex8/CMakeLists.txt @@ -0,0 +1,12 @@ +# xo-unit/example/ex8/CMakeLists.txt + +set(SELF_EXE xo_unit_ex8) +set(SELF_SRCS ex8.cpp) + +if (XO_ENABLE_EXAMPLES) + xo_add_executable(${SELF_EXE} ${SELF_SRCS}) + xo_self_headeronly_dependency(${SELF_EXE} xo_unit) + xo_dependency(${SELF_EXE} xo_flatstring) +endif() + +# end CMakeLists.txt diff --git a/example/ex8/ex8.cpp b/example/ex8/ex8.cpp new file mode 100644 index 00000000..ba5113ac --- /dev/null +++ b/example/ex8/ex8.cpp @@ -0,0 +1,29 @@ +/** @file ex8.cpp **/ + +#include "xo/unit/xquantity.hpp" +#include "xo/unit/xquantity_iostream.hpp" +#include + +int +main () { + using namespace xo::qty; + namespace u = xo::qty::u; + //namespace q = xo::qty::qty; + using namespace std; + + xquantity qty1(7, u::foot); + xquantity qty2(6.0, u::inch); + xquantity qty3 = qty1 + qty2; + + cerr << "qty1: " << qty1 << endl; + cerr << "qty2: " << qty2 << endl; + cerr << "qty3: " << qty3 << endl; + + /* rescale to mm */ + xquantity res = qty3.rescale(xo::qty::nu::millimeter); + + /* 2286mm */ + cerr << "res: " << res << endl; +} + +/** end ex8.cpp */ diff --git a/example/ex_su/CMakeLists.txt b/example/ex_su/CMakeLists.txt new file mode 100644 index 00000000..bad7a1ff --- /dev/null +++ b/example/ex_su/CMakeLists.txt @@ -0,0 +1,12 @@ +# xo-unit/example/su/CMakeLists.txt + +set(SELF_EXE xo_unit_ex_su) +set(SELF_SRCS ex_su.cpp) + +if (XO_ENABLE_EXAMPLES) + xo_add_executable(${SELF_EXE} ${SELF_SRCS}) + xo_self_headeronly_dependency(${SELF_EXE} xo_unit) + xo_dependency(${SELF_EXE} xo_flatstring) +endif() + +# end CMakeLists.txt diff --git a/example/ex_su/ex_su.cpp b/example/ex_su/ex_su.cpp new file mode 100644 index 00000000..67a67903 --- /dev/null +++ b/example/ex_su/ex_su.cpp @@ -0,0 +1,38 @@ +/** @file ex_su.cpp **/ + +#include "xo/unit/scaled_unit.hpp" +#include "xo/unit/scaled_unit_iostream.hpp" +#include + +using namespace std; + +int +main() { + using namespace xo::qty; + + constexpr auto u_prod = u::meter * u::kilometer; + + static_assert(u_prod[0].bu() == detail::bu::meter); + static_assert(u_prod[0].power() == power_ratio_type(2)); + static_assert(u_prod.outer_scale_factor_ == xo::ratio::ratio(1000)); + static_assert(u_prod.outer_scale_sq_ == 1.0); // used if fractional dimension + + constexpr auto u_div = u::meter / u::kilometer; + + static_assert(u_div.n_bpu() == 0); + static_assert(u_div.outer_scale_factor_ == xo::ratio::ratio(1,1000)); + static_assert(u_prod.outer_scale_sq_ == 1.0); // used if fractional dimension + + constexpr auto u2_prod = u::meter * u::hour * u::kilometer * u::minute; + + static_assert(u2_prod.n_bpu() == 2); + static_assert(u2_prod[0].bu() == detail::bu::meter); + static_assert(u2_prod[1].bu() == detail::bu::hour); + // *1000 from converting kilometers -> meters + // /60 from converting minutes -> hours + // 1000/60 = 50/3 in lowest terms + static_assert(u2_prod.outer_scale_factor_ == xo::ratio::ratio(50,3)); // used if fractional dimension + static_assert(u2_prod.outer_scale_sq_ == 1.0); // used if fractional dimension +} + +/** end ex_su.cpp **/ diff --git a/include/xo/unit/basis_unit.hpp b/include/xo/unit/basis_unit.hpp index 6b39e7a8..d856f8fc 100644 --- a/include/xo/unit/basis_unit.hpp +++ b/include/xo/unit/basis_unit.hpp @@ -16,13 +16,18 @@ namespace xo { /** @class basis_unit * @brief A dimensionless multiple of a single natively-specified basis dimension * - * For example "3600 minutes" or "1e-6 grams" + * For example "3600 minutes" or "1e-6 grams". + * + * Members are public so that a @c basis_unit instance qualifies as a 'structural type', + * and therefore may be used as a non-type template parameter. **/ struct basis_unit { public: /** @defgroup basis-unit-constructors basis_unit constructors **/ ///@{ + /** sentinel basis unit: invalid dimension and zero scalefactor **/ constexpr basis_unit() = default; + /** basis unit representing multiple @p scalefactor of native dimension @p **/ constexpr basis_unit(dimension native_dim, const scalefactor_ratio_type & scalefactor) : native_dim_{native_dim}, @@ -32,22 +37,27 @@ namespace xo { /** @defgroup basis-unit-access-methods basis_unit access methods **/ ///@{ + /** get @c native_dim member **/ constexpr dimension native_dim() const { return native_dim_; } + /** get @c scalefactor member **/ constexpr const scalefactor_ratio_type & scalefactor() const { return scalefactor_; } ///@} public: /* public so instance can be a non-type template parameter (a structural type) */ /** @defgroup basis-unit-instance-vars basis_unit instance variables **/ ///@{ - /** @brief identifies a native unit, e.g. time (in seconds) **/ + /** @brief identifies a native unit, e.g. time **/ dimension native_dim_ = dimension::invalid; /** @brief this unit defined as multiple scalefactor times native unit **/ - scalefactor_ratio_type scalefactor_; + scalefactor_ratio_type scalefactor_ = {}; ///@} }; /** @defgroup basis-unit-comparison-support basis_unit comparisons **/ ///@{ + /** @c true iff basis units are equal; + * both native dimension and scalefactor must be equal + **/ inline constexpr bool operator==(const basis_unit & x, const basis_unit & y) { @@ -55,6 +65,7 @@ namespace xo { && (x.scalefactor_ == y.scalefactor_)); } + /** @c true iff bass units are not equal **/ inline constexpr bool operator!=(const basis_unit & x, const basis_unit & y) { @@ -64,6 +75,7 @@ namespace xo { ///@} namespace detail { + /** @brief namespace for basis-unit constants and helpers **/ namespace bu { // ----- mass ----- @@ -73,15 +85,25 @@ namespace xo { /** @defgroup basis-unit-mass-units basis_unit mass units **/ ///@{ + /** basis unit of 10^-12 grams **/ constexpr basis_unit picogram = mass_unit( 1, 1000000000000); + /** basis unit of 10^-9 grams **/ constexpr basis_unit nanogram = mass_unit( 1, 1000000000); + /** basis unit of 10^-6 grams **/ constexpr basis_unit microgram = mass_unit( 1, 1000000); + /** basis unit of 10^-3 grams **/ constexpr basis_unit milligram = mass_unit( 1, 1000); + /** basis unit of 1 gram **/ constexpr basis_unit gram = mass_unit( 1, 1); + /** basis unit of 10^3 grams **/ constexpr basis_unit kilogram = mass_unit( 1000, 1); + /** basis unit of 10^6 grams = 10^3 kilograms **/ constexpr basis_unit tonne = mass_unit( 1000000, 1); + /** basis unit of 10^9 grams = 10^6 kilograms = 10^3 tonnes **/ constexpr basis_unit kilotonne = mass_unit( 1000000000, 1); + /** basis unit of 10^12 grams = 10^9 kilograms = 10^6 tonnes **/ constexpr basis_unit megatonne = mass_unit( 1000000000000, 1); + /** basis unit of 10^15 grams = 10^12 kilograms = 10^9 tonnes **/ constexpr basis_unit gigatonne = mass_unit(1000000000000000, 1); ///@} @@ -94,26 +116,44 @@ namespace xo { /** @defgroup basis-unit-distance-units basis_unit distance units **/ ///@{ /* US spelling */ + /** basis unit of 10^-12 meters **/ constexpr basis_unit picometer = distance_unit( 1, 1000000000000); + /** basis unit of 10^-9 meters **/ constexpr basis_unit nanometer = distance_unit( 1, 1000000000); + /** basis unit of 10^-6 meters **/ constexpr basis_unit micrometer = distance_unit( 1, 1000000); + /** basis unit of 10^-3 meters **/ constexpr basis_unit millimeter = distance_unit( 1, 1000); + /** basis unit of 1 meter **/ constexpr basis_unit meter = distance_unit( 1, 1); + /** basis unit of 10^3 meters **/ constexpr basis_unit kilometer = distance_unit( 1000, 1); + /** basis unit of 10^6 meters (for form's sake -- not commonly used) **/ constexpr basis_unit megameter = distance_unit( 1000000, 1); + /** basis unit of 10^9 meters (for form's sake -- not commonly used) **/ constexpr basis_unit gigameter = distance_unit( 1000000000, 1); + /** basis unit of 1 light-second = distance light travels in a vacuum in 1 second **/ constexpr basis_unit lightsecond = distance_unit( 299792458, 1); + /** basis unit of 1 astronomical unit, representing approximate radius of earth orbit. **/ constexpr basis_unit astronomicalunit = distance_unit( 149597870700, 1); /* Int'l spelling */ + /** international spelling for picometer **/ constexpr basis_unit picometre = picometer; + /** international spelling for nanometer **/ constexpr basis_unit nanometre = nanometer; + /** international spelling for micrometer **/ constexpr basis_unit micrometre = micrometer; + /** international spelling for millimeter **/ constexpr basis_unit millimetre = millimeter; + /** international spelling for meter **/ constexpr basis_unit metre = meter; + /** international spelling for kilometer **/ constexpr basis_unit kilometre = kilometer; + /** international spelling for megameter **/ constexpr basis_unit megametre = megameter; + /** international spelling for gigameter **/ constexpr basis_unit gigametre = gigameter; /** @brief basis-unit representing 1 inch; defined as exactly 1/12 feet **/ @@ -134,22 +174,37 @@ namespace xo { /** @defgroup basis-unit-time-units basis_unit time units **/ ///@{ + /** basis unit of 10^-12 seconds **/ constexpr basis_unit picosecond = time_unit( 1, 1000000000000); + /** basis unit of 10^-9 seconds **/ constexpr basis_unit nanosecond = time_unit( 1, 1000000000); + /** basis unit of 10^-6 seconds **/ constexpr basis_unit microsecond = time_unit( 1, 1000000); + /** basis unit of 10^-3 seconds **/ constexpr basis_unit millisecond = time_unit( 1, 1000); + /** basis unit of 1 second **/ constexpr basis_unit second = time_unit( 1, 1); + /** basis unit of 1 minute = 60 seconds **/ constexpr basis_unit minute = time_unit( 60, 1); + /** basis unit of 1 hour = 3600 seconds **/ constexpr basis_unit hour = time_unit( 3600, 1); + /** basis unit of 1 day = exactly 24 hours **/ constexpr basis_unit day = time_unit( 24*3600, 1); + /** basis unit of 1 week = exactly 7 days **/ constexpr basis_unit week = time_unit( 7*24*3600, 1); + /** basis unit of 1 month = exactly 30 days **/ constexpr basis_unit month = time_unit( 30*24*3600, 1); + /** basis unit of 1 year, defined as 365.25 days **/ constexpr basis_unit year = time_unit( (365*24+6)*3600, 1); /* alt conventions used in finance */ + /** basis unit of 1 year365 = exactly 365 days **/ constexpr basis_unit year365 = time_unit( 365*24*3600, 1); + /** basis unit of 1 year360 = exactly 360 days **/ constexpr basis_unit year360 = time_unit( 360*24*3600, 1); - /* 250 = approx number of trading days in a calendar year */ + /** basis unit of 1 year250 = exactly 250 days. + * Approximate number of business days in one year + **/ constexpr basis_unit year250 = time_unit( 250*24*3600, 1); //constexpr basis_unit century = time_unit( 100L*(365*24+6)*3600, 1); @@ -165,7 +220,7 @@ namespace xo { return basis_unit(dimension::currency, scalefactor_ratio_type(num, den)); } - /* pseudounit -- placeholder for any actual currency amount */ + /** pseudounit -- placeholder for any actual currency amount **/ constexpr basis_unit currency = currency_unit(1, 1); // ----- price ----- @@ -174,7 +229,7 @@ namespace xo { return basis_unit(dimension::price, scalefactor_ratio_type(num, den)); } - /* psuedounit -- context-dependent interpretation */ + /** psuedounit -- context-dependent interpretation for a screen price **/ constexpr basis_unit price = price_unit(1, 1); ///@} } /*namespace bu*/ diff --git a/include/xo/unit/bpu.hpp b/include/xo/unit/bpu.hpp index 662dd0ca..29138d94 100644 --- a/include/xo/unit/bpu.hpp +++ b/include/xo/unit/bpu.hpp @@ -41,7 +41,7 @@ namespace xo { } } - /** @brief construct suffix abbreviation for a basis-power-unit **/ + /** construct suffix abbreviation for a basis-power-unit **/ static constexpr bpu_abbrev_type bpu_abbrev(dim native_dim, const scalefactor_ratio_type & scalefactor, @@ -67,23 +67,29 @@ namespace xo { public: /** @defgroup bpu-ctors bpu constructors **/ ///@{ + /** default constructor. creates dimensionless bpu, + * representing zero'th power of sentinel basis unit + **/ constexpr bpu() = default; + /** construct @c bpu representing exponent @p power of basis unit @p bu **/ constexpr bpu(const basis_unit & bu, const power_ratio_type & power) : bu_{bu}, power_{power} {} + /** construct @c bpu representing exponent @p power of @c basis_unit(native_dim,scalefactor) **/ constexpr bpu(dim native_dim, const scalefactor_ratio_type & scalefactor, const power_ratio_type & power) : bu_(native_dim, scalefactor), power_{power} {} - ///@} + /** construct bpu representing basis unit @p bu, i.e. with unit exponent **/ static constexpr bpu unit_power(const basis_unit & bu) { return bpu(bu, power_ratio_type(1,1)); } + ///@} /** @defgroup bpu-access-methods bpu access methods **/ ///@{ @@ -99,7 +105,7 @@ namespace xo { /** @defgroup bpu-methods **/ ///@{ - /** @brief abbreviation for this dimension + /** abbreviation for this dimension * * @code * bpu(dim::time, @@ -114,7 +120,7 @@ namespace xo { power_); } - /** @brief for bpu @c x, @c x.reciprocal() represents dimension of @c 1/x + /** for bpu @c x, @c x.reciprocal() represents dimension of @c 1/x * * Example: * @code @@ -129,7 +135,7 @@ namespace xo { return bpu(bu_.native_dim(), bu_.scalefactor(), power_.negate()); } - /** @brief construct bpu representing the same unit, but using @c Int2 to represent exponenct **/ + /** construct bpu representing the same unit, but using @c Int2 to represent exponenct **/ template constexpr bpu to_repr() const { return bpu(this->native_dim(), @@ -141,21 +147,29 @@ namespace xo { public: /* need public members so that a basis_unit instance can be a non-type template parameter (a structural type) */ /** @defgroup bpu-instance-vars **/ ///@{ - /** @brief this bpu represent a power of this basis unit **/ + /** this @c bpu represent a power of basis unit @c bu. + * + * Public to avoid disqualifying @c bpu as a 'structural type'. + **/ struct basis_unit bu_; - /** @brief this unit represents basis dimension (bu) taken to this power **/ - power_ratio_type power_; + /** this unit represents basis dimension (bu) taken to this power + * + * Public to avoid disqualifying @c bpu as a 'structural type'. + **/ + power_ratio_type power_ = {}; ///@} }; /** @defgroup bpu-comparison **/ ///@{ - /** @brief compare bpus @p x and @p y for equality **/ + /** @brief compare bpus @p x and @p y for equality + * + * Equality requires that both basis unit and power are equal + **/ template inline constexpr bool operator==(const bpu & x, const bpu & y) { - return ((x.native_dim() == y.native_dim()) - && (x.scalefactor() == y.scalefactor()) + return ((x.bu() == y.bu()) && (x.power_ == y.power_)); } @@ -163,8 +177,7 @@ namespace xo { template inline constexpr bool operator!=(const bpu & x, const bpu & y) { - return ((x.native_dim() != y.native_dim()) - || (x.scalefactor() != y.scalefactor()) + return ((x.bu() != y.bu()) || (x.power_ != y.power_)); } ///@} diff --git a/include/xo/unit/natural_unit.hpp b/include/xo/unit/natural_unit.hpp index 9cdb81ae..27601f49 100644 --- a/include/xo/unit/natural_unit.hpp +++ b/include/xo/unit/natural_unit.hpp @@ -31,9 +31,7 @@ namespace xo { p_target->push_back(bpu0); push_bpu_array(p_target, args...); } - } - namespace detail { template struct nu_maker { template @@ -52,40 +50,61 @@ namespace xo { * 1. Quantities are represented as a multiple of a natural unit * 2. Each bpu in the array represents a power of a basis dimension, e.g. "meter" or "second^2". * 3. Each bpu in an array has a different dimension id. - * For example dim::time, if present, appears once. + * For example @c dim::time, if present, appears once. * 4. Basis dimensions can appear in any order. * Order used for constructing abbreviations: will get @c "kg.m" or @c "m.kg" - * depending on the orderin of @c dim::distance and @c dim::mass in @c bpu_v_ + * depending on the ordering of @c dim::distance and @c dim::mass in @c bpu_v_ + * + * @c Int supplies representation for numerator and denominator in basis-unit scale factors. **/ template class natural_unit { public: + /** @defgroup natural-unit-type-traits natural unit type traits **/ + ///@{ + /** @brief representation for numerator and denominator of scalefactor ratios **/ using ratio_int_type = Int; + ///@} public: /** @addtogroup natural-unit-ctors **/ ///@{ + + /** construct dimensionless unit **/ constexpr natural_unit() : n_bpu_{0} {} + /** construct unit representing basis unit @p bu with exponent @p power **/ static constexpr natural_unit from_bu(basis_unit bu, power_ratio_type power = power_ratio_type(1)) { return detail::nu_maker::make_nu(bpu(bu, power)); } + ///@} /** @addtogroup natural-unit-access-methods **/ ///@{ - /** always true. @see scaled_unit::is_natural **/ + + /** always true. Provided for symmetry with @c xo::qty::scaled_unit::is_natural **/ constexpr bool is_natural() const { return true; } + /** get member @c n_bpu **/ constexpr std::size_t n_bpu() const { return n_bpu_; } + /** true if this unit has no dimension **/ constexpr bool is_dimensionless() const { return n_bpu_ == 0; } + /** get address of member @c bpu_v **/ constexpr bpu * bpu_v() const { return bpu_v_; } + ///@} /** @defgroup natural-unit-methods **/ ///@{ + + /** construct reciprocal of this unit. + * + * For example reciprocal of a newton (abbreviation @c "kg.m.s^-2") is + * a unit with abbreviation @c "kg^-1.m^-1.s^2" + **/ constexpr natural_unit reciprocal() const { natural_unit retval; @@ -95,6 +114,12 @@ namespace xo { return retval; } + /** abbreviation for this unit. + * + * Apply as suffix when printing quantities involving this unit. + * + * For example @c "mm" for millimeters, or @c "ns" for nanoseconds + **/ constexpr nu_abbrev_type abbrev() const { nu_abbrev_type retval; @@ -107,7 +132,7 @@ namespace xo { return retval; } - /** @brief remove bpu at position @p p **/ + /** remove bpu at position @p p **/ constexpr void remove_bpu(size_t p) { for (std::size_t i = p; i+1 < n_bpu_; ++i) bpu_v_[i] = bpu_v_[i+1]; @@ -115,20 +140,44 @@ namespace xo { --n_bpu_; } + /** append @p bpu to this unit in-place + * + * Require @c bpu.native_dim does not match any existing member of @ref bpu_v_ + **/ constexpr void push_back(const bpu & bpu) { if (n_bpu_ < n_dim) bpu_v_[n_bpu_++] = bpu; } + ///@} /** @addtogroup natural-unit-access-methods **/ ///@{ + + /** get bpu for dimension @p d. if d isn't present, construct bpu with 0 power **/ + constexpr bpu lookup_dim(dimension d) const { + for (std::size_t i = 0, n = n_bpu(); i(d, scalefactor_ratio_type(0), power_ratio_type(0)); + } + + /** get element @p i of @ref bpu_v_ **/ constexpr bpu & operator[](std::size_t i) { return bpu_v_[i]; } + /** get element @p i of @ref bpu_v_ (const version) **/ constexpr const bpu & operator[](std::size_t i) const { return bpu_v_[i]; } + ///@} /** @defgroup natural-unit-conversion-methods **/ ///@{ + + /** convert to equivalent unit using scalefactor representation @p Int2 instead of + * @ref ratio_int_type + **/ template constexpr natural_unit to_repr() const { natural_unit retval; @@ -139,38 +188,58 @@ namespace xo { return retval; } + ///@} public: /* public members so instance can be non-type template parameter (is a structural type) */ /** @defgroup natural-unit-instance-vars **/ ///@{ - /** @brief the number of occupied slots in @c bpu_v_ **/ + + /** the number of occupied slots in @c bpu_v_ **/ std::size_t n_bpu_; - /** @brief storage for basis power units **/ + /** storage for basis power units **/ bpu bpu_v_[n_dim]; + ///@} }; + /** @defgroup natural-unit-comparison-functions natural-unit comparison functions **/ + ///@{ + + /** compare natural units @p x, @p y for equality. **/ template constexpr bool - operator==(const natural_unit & x, const natural_unit & y) { + operator==(const natural_unit & x, + const natural_unit & y) + { if (x.n_bpu() != y.n_bpu()) return false; - for (std::size_t i = 0, n = x.n_bpu(); i & xi = x[i]; + if (xi != y.lookup_dim(xi.native_dim())) return false; + } + + /* if all bpu's x[i] match something from y, then x,y must be equal + * since they each have the same number of bpu's + */ return true; } + /** compare natural units @p x, @p y for inequality **/ template constexpr bool - operator!=(const natural_unit & x, const natural_unit & y) { + operator!=(const natural_unit & x, + const natural_unit & y) { return !(x == y); } + ///@} + namespace detail { /** * Given bpu ~ (b.u)^p: @@ -387,6 +456,11 @@ namespace xo { } /*namespace detail*/ + /** @brief namespace for constants representing basis natural units + * + * Application code will typically use parallel scaled-unit constants + * (see the 'u' namespace in 'scaled_unit.hpp') + **/ namespace nu { constexpr auto dimensionless = natural_unit(); @@ -445,7 +519,8 @@ namespace xo { constexpr auto volatility_30d = natural_unit::from_bu(detail::bu::month, power_ratio_type(-1,2)); constexpr auto volatility_250d = natural_unit::from_bu(detail::bu::year250, power_ratio_type(-1,2)); constexpr auto volatility_360d = natural_unit::from_bu(detail::bu::year360, power_ratio_type(-1,2)); - constexpr auto volatility_365d = natural_unit::from_bu(detail::bu::year365, power_ratio_type(-1,2)); } /*namespace nu*/ + constexpr auto volatility_365d = natural_unit::from_bu(detail::bu::year365, power_ratio_type(-1,2)); + } /*namespace nu*/ } /*namespace qty*/ } /*namespace xo*/ diff --git a/include/xo/unit/quantity.hpp b/include/xo/unit/quantity.hpp index 380545af..96078c4b 100644 --- a/include/xo/unit/quantity.hpp +++ b/include/xo/unit/quantity.hpp @@ -15,7 +15,7 @@ namespace xo { * * @brief represent a scalar quantity with associated units. * - * - @p NaturalUnit is a non-type template parameter + * - @p NaturalUnit is a non-type template paramoeter * identifying a unit used for this quantity. * In *xo-unit* it will be an instance of @c natural_unit * - @p Repr is a type used to represent a multiple @@ -93,19 +93,19 @@ namespace xo { } ///@} + /** @defgroup quantity-unit-conversion **/ + ///@{ + + /** create equivalent quantity using scale representation @p Repr2 instead of @c Repr **/ template constexpr auto with_repr() const { return quantity(scale_); } - /** @defgroup quantity-unit-conversion **/ - ///@{ - /* parallel implementation to Quantity::rescale(), - * except that NaturalUnit2 is a compile-time-only template-argument - * - * NOTE: constexpr as long as no fractional units involved. - */ + /** create equivalent quantity expressed as a multiple of @p NaturalUnit2 + * instead of @ref s_unit + **/ template NaturalUnit2> constexpr auto rescale() const { @@ -126,6 +126,9 @@ namespace xo { } } + /** create equivalent quantity expressed as as multiple of @p ScaledUnit2 + * instead of @ref s_unit + **/ template ScaledUnit2> constexpr auto rescale_ext() const { @@ -156,6 +159,10 @@ namespace xo { } ///@} + /** create quantity representing this amount multiplied by dimensionless value @p x + * + * @pre x must be an arithmetic type such as @c int or @c double + **/ template requires std::is_arithmetic_v constexpr auto scale_by(Dimensionless x) const { @@ -173,7 +180,7 @@ namespace xo { /** @defgroup quantity-comparison-support **/ ///@{ - /* parallel implementation to Quantity */ + /** compare two @c quantity instances, under three-way comparison **/ template static constexpr auto compare(const quantity &x, const Quantity2 & y) { @@ -189,19 +196,21 @@ namespace xo { // operator*= // operator/= + /** **/ constexpr nu_abbrev_type abbrev() const { return s_scaled_unit.natural_unit_.abbrev(); } /** @defgroup quantity-assignment quantity assignment operators **/ ///@{ - /** @brief assignment from quantity with identical units **/ + + /** assignment from quantity with identical units **/ quantity & operator=(const quantity & x) { this->scale_ = x.scale_; return *this; } - /** @brief assignment from quantity with compatible units **/ + /** assignment from quantity with compatible units **/ template requires(quantity_concept && Q2::always_constexpr_unit) @@ -212,44 +221,68 @@ namespace xo { return *this; } + ///@} /** @defgroup quantity-unit-conversion **/ ///@{ + + /** */ template requires(quantity_concept && Q2::always_constexpr_unit) constexpr operator Q2() const { return this->template rescale_ext().template with_repr(); } - ///@} + /** For dimensionless quantities: convert to underlying scale value + * + * Not present for dimensioned quantities. + **/ constexpr operator Repr() const requires (ScaledUnit.is_dimensionless()) { return scale_; } + ///@} + public: /* need public members so that instance can be a non-type template parameter (is a structural type) */ /** @defgroup quantity-static-vars **/ ///@{ + /** @brief unit for quantity of this type. Determined at compile-time **/ static constexpr scaled_unit s_scaled_unit = ScaledUnit; + ///@} /** @defgroup quantity-instance-vars **/ ///@{ - /** @brief quantity represents this multiple of @ref s_scaled_unit **/ + + /** quantity represents this multiple of @ref s_scaled_unit + * + * Public to avoid disqualifying @c quantity as a 'structural type'; + * prerequisite for using a @c quantity instance as a non-type template parameter + **/ Repr scale_ = Repr{}; + ///@} }; + ///@{ + + /** + * + **/ template constexpr auto - rescale(const Quantity & x, const scaled_unit & su) { + rescale(const Quantity & x, + const scaled_unit & su) { return x.template rescale(); } + ///@} + namespace detail { struct quantity_util { /* parallel implementation to xquantity multiply, @@ -451,29 +484,49 @@ namespace xo { namespace qty { // ----- mass ----- + /** create quantity representing @p x picograms of mass, with compile-time unit representation **/ template inline constexpr auto picograms(Repr x) { return quantity(x); } + + /** create quantity representing @p x nanograms of mass, with compile-time unit representation **/ template inline constexpr auto nanograms(Repr x) { return quantity(x); } + + /** create quantity representing @p x micrograms of mass, with compile-time unit representation **/ template inline constexpr auto micrograms(Repr x) { return quantity(x); } + + /** create quantity representing @p x milligrams of mass, with compile-time unit representation **/ template inline constexpr auto milligrams(Repr x) { return quantity(x); } + + /** create quantity representing @p x grams of mass, with compile-time unit representation **/ template inline constexpr auto grams(Repr x) { return quantity(x); } - /** @brief create a quantity representing @p x kilograms of mass, with compile-time unit representation **/ + /** create quantity representing @p x kilograms of mass, with compile-time unit representation **/ template inline constexpr auto kilograms(Repr x) { return quantity(x); } + /** create quantity representing @p x tonnes of mass, with compile-time unit representation **/ template inline constexpr auto tonnes(Repr x) { return quantity(x); } + + /** create quantity representing @p x kilotonnes of mass, with compile-time unit representation **/ template inline constexpr auto kilotonnes(Repr x) { return quantity(x); } + + /** create quantity representing @p x megatonnes of mass, with compile-time unit representation **/ template inline constexpr auto megatonnes(Repr x) { return quantity(x); } + + /** create quantity representing @p x gigatonnes of mass, with compile-time unit representation **/ template inline constexpr auto gigatonnes(Repr x) { return quantity(x); } + } + + namespace qty { + // ----- mass constants ---- /** @brief a quantity representing 1 picogram of mass, with compile-time unit representation **/ static constexpr auto picogram = picograms(1); @@ -496,46 +549,74 @@ namespace xo { namespace qty { // ----- distance ----- + /** create quantity representing @p x picometers of distance, with compile-time unit operations **/ template inline constexpr auto picometers(Repr x) { return quantity(x); } + + /** create quantity representing @p x nanometers of distance, with compile-time unit operations **/ template inline constexpr auto nanometers(Repr x) { return quantity(x); } + + /** create quantity representing @p x micrometers of distance, with compile-time unit operations **/ template inline constexpr auto micrometers(Repr x) { return quantity(x); } + + /** create quantity representing @p x millimeters of distance, with compile-time unit operations **/ template inline constexpr auto millimeters(Repr x) { return quantity(x); } + + /** create quantity representing @p x meters of distance, with compile-time unit operations **/ template inline constexpr auto meters(Repr x) { return quantity(x); } + + /** create quantity representing @p x kilometers of distance, with compile-time unit operations **/ template inline constexpr auto kilometers(Repr x) { return quantity(x); } + + /** create quantity representing @p x megameters of distance, with compile-time unit operations **/ template inline constexpr auto megameters(Repr x) { return quantity(x); } + + /** create quantity representing @p x gigameters of distance, + * with compile-time unit operations + **/ template inline constexpr auto gigameters(Repr x) { return quantity(x); } + /** create quantity representing @p x light-seconds of distance, + * with compile-time unit operations. + **/ template inline constexpr auto lightseconds(Repr x) { return quantity(x); } + + /** create quantity representing @p x astronomical units of distance, + * with compile-time unit representation + **/ template inline constexpr auto astronomicalunits(Repr x) { return quantity(x); } - /** @brief create quantity representing @p x inches of distance, with compile-time unit representation **/ + /** create quantity representing @p x inches of distance, with compile-time unit representation **/ template inline constexpr auto inches(Repr x) { return quantity(x); } - /** @brief create quantity representing @p x feet of distance, with compile-time unit representation **/ + /** create quantity representing @p x feet of distance, with compile-time unit representation **/ template inline constexpr auto feet(Repr x) { return quantity(x); } - /** @brief create quantity representing @p x yards of distance, with compile-time unit representation **/ + /** create quantity representing @p x yards of distance, with compile-time unit representation **/ template inline constexpr auto yards(Repr x) { return quantity(x); } - /** @brief create quantity representing @p x statute miles of distance, with compile-time unit representation **/ + /** create quantity representing @p x statute miles of distance, with compile-time unit representation **/ template inline constexpr auto miles(Repr x) { return quantity(x); } + } - /** @brief a quantity representing 1 picometer of distance, with compile-time unit representation **/ + namespace qty { + // ----- distance constants ----- + + /** a quantity representing 1 picometer of distance, with compile-time unit representation **/ static constexpr auto picometer = picometers(1); - /** @brief a quantity representing 1 nanometer of distance, with compile-time unit representation **/ + /** a quantity representing 1 nanometer of distance, with compile-time unit representation **/ static constexpr auto nanometer = nanometers(1); - /** @brief a quantity representing 1 micrometer of distance, with compile-time unit representation **/ + /** a quantity representing 1 micrometer of distance, with compile-time unit representation **/ static constexpr auto micrometer = micrometers(1); /** @brief a quantity representing 1 millimeter of distance, with compile-time unit representation **/ static constexpr auto millimeter = millimeters(1); @@ -558,52 +639,83 @@ namespace xo { namespace qty { // ----- time ----- + /** create quantity representing @p x picoseconds of time, with compile-time unit operations **/ template inline constexpr auto picoseconds(Repr x) { return quantity(x); } + + /** create quantity representing @p x nanoseconds of time, with compile-time unit operations **/ template inline constexpr auto nanoseconds(Repr x) { return quantity(x); } + + /** create quantity representing @p x microseconds of time, with compile-time unit operations **/ template inline constexpr auto microseconds(Repr x) { return quantity(x); } + /** create quantity representing @p x milliseconds of time, with compile-time unit operations **/ template inline constexpr auto milliseconds(Repr x) { return quantity(x); } - /** @brief create quantity representing @p x seconds of time, with compile-time unit representation **/ + /** create quantity representing @p x seconds of time, with compile-time unit operations **/ template - inline constexpr auto seconds(Repr x) { return quantity(x); } - /** @brief create quantity representing @p x minutes of time, with compile-time unit representation **/ + /** create quantity representing @p x minutes of time, with compile-time unit operations **/ template inline constexpr auto minutes(Repr x) { return quantity(x); } - /** @brief create quantity representing @p x hours of time, with compile-time unit representation **/ + /** create quantity representing @p x hours of time, with compile-time unit operations **/ template inline constexpr auto hours(Repr x) { return quantity(x); } - /** @brief create quantity representing @p x days of time, with compile-time unit representation **/ + /** create quantity representing @p x exactly-24-hour days of time, with compile-time unit operations **/ template inline constexpr auto days(Repr x) { return quantity(x); } + /** creeate quantity representing @p x weeks of time, + * with compile-time unit operations. Each week has exactly 7 24-hour days. + **/ template inline constexpr auto weeks(Repr x) { return quantity(x); } + + /** create quantity representing @p x months of time, + * with compile-time unit operations. Each month has exactly 30 24-hour days + **/ template inline constexpr auto months(Repr x) { return quantity(x); } + + /** create quantity representing @p x years of time, + * with compile-time unit operations. Each year has exactly 365.25 24-hour days + **/ template inline constexpr auto years(Repr x) { return quantity(x); } + + /** create quantity representing @p x '250-day years' of time. + * 250 represents approximate number of business days in a calendar year. + **/ template inline constexpr auto year250s(Repr x) { return quantity(x); } + + /** create quantity representing @p x '360-day years' of time **/ template inline constexpr auto year360s(Repr x) { return quantity(x); } + + /** create quantity representing @p x '365-day years' of time **/ template inline constexpr auto year365s(Repr x) { return quantity(x); } + } + + namespace qty { + // ----- time constants ---- /** @brief a quantity representing 1 second of time, with compile-time unit representation **/ static constexpr auto second = seconds(1); + /** @brief a quantity representing 1 minute of time, with compile-time unit representation **/ static constexpr auto minute = minutes(1); + /** @brief a quantity representing 1 hour of time, with compile-time unit representation **/ static constexpr auto hour = hours(1); + /** @brief a quantity representing 1 day of time (exactly 24 hours), with compile-time unit representation **/ static constexpr auto day = days(1); } /*namespace qty*/ @@ -615,12 +727,19 @@ namespace xo { * volatility ~ sqrt(variance), has dimension 1/sqrt(t) */ + /** create quantity representing @p x units of 30-day volatility, with compile-time unit representation **/ template inline constexpr auto volatility_30d(Repr x) { return quantity(x); } + + /** create quantity representing @p x units of 250-day volatility, with compile-time unit representation **/ template inline constexpr auto volatility_250d(Repr x) { return quantity(x); } + + /** create quantity representing @p x units of 360-day volatility, with compile-time unit representation **/ template inline constexpr auto volatility_360d(Repr x) { return quantity(x); } + + /** create quantity representing @p x units of 365-day volatility, with compile-time unit representation **/ template inline constexpr auto volatility_365d(Repr x) { return quantity(x); } } /*namespace qty*/ diff --git a/include/xo/unit/scaled_unit.hpp b/include/xo/unit/scaled_unit.hpp index 44129426..fa9320fa 100644 --- a/include/xo/unit/scaled_unit.hpp +++ b/include/xo/unit/scaled_unit.hpp @@ -15,8 +15,22 @@ namespace xo { template < typename Int, typename OuterScale = ratio::ratio > struct scaled_unit { + /** @defgroup scaled-unit-type-traits scaled-unit type traits **/ + ///@{ + + /** type for representing individual basis-unit scalefactors **/ using ratio_int_type = typename natural_unit::ratio_int_type; + ///@} + + public: + /** @defgroup scaled-unit-ctors scaled-unit constructors **/ + ///@{ + + /** create scaled unit representing a multiple + * @p outer_scale_factor * @p sqrt(outer_scale_sq) + * of natural unit @p nat_unit + **/ constexpr scaled_unit(const natural_unit & nat_unit, OuterScale outer_scale_factor, double outer_scale_sq) @@ -25,33 +39,72 @@ namespace xo { outer_scale_sq_{outer_scale_sq} {} + ///@} + + /** @defgroup scaled-unit-access-methods scaled-unit access methods **/ + ///@{ + + /** always true for scaled_unit **/ constexpr bool is_scaled_unit_type() const { return true; } + /** true iff scaled unit can be faithfully represented by a @ref natural_unit **/ + constexpr bool is_natural() const { + return (outer_scale_factor_ == OuterScale(1) && (outer_scale_sq_ == 1.0)); + } + + /** true if this scaled unit has no dimension **/ + constexpr bool is_dimensionless() const { return natural_unit_.is_dimensionless(); } + + /** get number of distinct native dimensions present. + * e.g. for unit Newton = 1 kg.m.s^-2, n_bpu would be 3, + * with {mass, distance, time} present. + * Note that this value does not count exponents + **/ + constexpr std::size_t n_bpu() const { return natural_unit_.n_bpu(); } + + ///@} + + /** @defgroup scaled-unit-general-methods scaled-unit access methods **/ + ///@{ + + /** return reciprocal of this unit. **/ constexpr scaled_unit reciprocal() const { return scaled_unit(natural_unit_.reciprocal(), 1 / outer_scale_factor_, 1.0 / outer_scale_sq_); } - /** @brief true iff scaled unit can be faithfully represented by a @ref natural_unit **/ - constexpr bool is_natural() const { - return (outer_scale_factor_ == OuterScale(1) && (outer_scale_sq_ == 1.0)); + /** get bpu for dimension @p d. if d isn't present, construct bpu with 0 power **/ + constexpr bpu lookup_dim(dimension d) const { + return natural_unit_.lookup_dim(d); } - constexpr bool is_dimensionless() const { return natural_unit_.is_dimensionless(); } - constexpr std::size_t n_bpu() const { return natural_unit_.n_bpu(); } - + /** return @p i'th bpu associated with this unit **/ constexpr bpu & operator[](std::size_t i) { return natural_unit_[i]; } + /** return @p i'th bpu associated with this unit (const version) **/ constexpr const bpu & operator[](std::size_t i) const { return natural_unit_[i]; } - public: /* need public members so that a scaled_unit instance can be a non-type template parameter (a structural type) */ + ///@} - natural_unit natural_unit_; + public: /* public members so scaled_unit instance can be a non-type template parameter (a structural type) */ + + /** @defgroup scaled-unit-instance-vars **/ + ///@{ + + /** scale factor multiplying @ref natural_unit_ **/ OuterScale outer_scale_factor_; + + /** squared scale factor multiplying @ref natural_unit_ **/ double outer_scale_sq_; + + /** natural unit term in this scaled unit **/ + natural_unit natural_unit_; + + ///@} }; namespace detail { + /** promote natural unit to scaled unit (with unit outer scalefactors) **/ template constexpr auto su_promote(const natural_unit & bpuv) { return scaled_unit(bpuv, @@ -71,60 +124,154 @@ namespace xo { su_from_bu(const basis_unit & bu, const power_ratio_type & power = power_ratio_type(1)) { - return detail::su_promote(natural_unit::from_bu(bu, power)); + return detail::su_promote(natural_unit::from_bu(bu, power)); } + /** @defgroup scaled-unit-dimensionless scaled-unit dimensionless constant **/ + ///@{ + + /** dimensionless unit; equivalent to 1 **/ + constexpr auto dimensionless = detail::su_promote(nu::dimensionless); + + ///@} + + // ----- mass units ----- + + /** @defgroup scaled-unit-mass scaled-unit mass units **/ + ///@{ + + /** unit of 10^-12 grams **/ constexpr auto picogram = su_from_bu(detail::bu::picogram); + /** unit of 10^-9 grams **/ constexpr auto nanogram = su_from_bu(detail::bu::nanogram); + /** unit of 10^-6 grams **/ constexpr auto microgram = su_from_bu(detail::bu::microgram); + /** unit of 10^-3 grams **/ constexpr auto milligram = su_from_bu(detail::bu::milligram); + /** unit of 1 gram **/ constexpr auto gram = su_from_bu(detail::bu::gram); + /** unit of 10^3 grams **/ constexpr auto kilogram = su_from_bu(detail::bu::kilogram); + /** unit of 1 metric tonne = 10^3 kg **/ constexpr auto tonne = su_from_bu(detail::bu::tonne); + /** unit of 10^3 tonnes = 10^6 kg **/ constexpr auto kilotonne = su_from_bu(detail::bu::kilotonne); + /** unit of 10^6 tonnes = 10^9 kg **/ constexpr auto megatonne = su_from_bu(detail::bu::megatonne); + /** unit of 10^9 tonnes = 10^12 kg **/ constexpr auto gigatonne = su_from_bu(detail::bu::gigatonne); + ///@} + + // ----- distance units ----- + + /** @defgroup scaled-unit-distance scaled-unit distance units **/ + ///@{ + + /** unit of 10^-12 meters **/ constexpr auto picometer = su_from_bu(detail::bu::picometer); + /** unit of 10^-9 meters **/ constexpr auto nanometer = su_from_bu(detail::bu::nanometer); + /** unit of 10^-6 meters **/ constexpr auto micrometer = su_from_bu(detail::bu::micrometer); + /** unit of 10^-3 meters **/ constexpr auto millimeter = su_from_bu(detail::bu::millimeter); + /** unit of 1 meter **/ constexpr auto meter = su_from_bu(detail::bu::meter); + /** unit of 10^3 meters **/ constexpr auto kilometer = su_from_bu(detail::bu::kilometer); + /** unit of 10^6 meters (not commonly used) **/ constexpr auto megameter = su_from_bu(detail::bu::megameter); + /** unit of 10^9 meters (not commonly used) **/ constexpr auto gigameter = su_from_bu(detail::bu::gigameter); + /** unit of 1 light-second = distance light travels in a vacuum in 1 second **/ constexpr auto lightsecond = su_from_bu(detail::bu::lightsecond); + /** unit of 1 astronomical unit, for approximate radius of earth orbit **/ constexpr auto astronomicalunit = su_from_bu(detail::bu::astronomicalunit); + /** unit of 1 inch = 1/12 feet **/ constexpr auto inch = su_from_bu(detail::bu::inch); + /** unit of 1 foot = 0.3048 meters **/ constexpr auto foot = su_from_bu(detail::bu::foot); + /** unit of 1 yard = 3 feet **/ constexpr auto yard = su_from_bu(detail::bu::yard); + /** unit of 1 mile = 1760 yards **/ constexpr auto mile = su_from_bu(detail::bu::mile); + ///@} + + // ----- time units ----- + + /** @defgroup scaled-unit-time scaled-unit time units **/ + ///@{ + + /** unit of 1 picosecond = 10^-12 seconds **/ constexpr auto picosecond = su_from_bu(detail::bu::picosecond); + /** unit of 1 nanosecond = 10^-9 seconds **/ constexpr auto nanosecond = su_from_bu(detail::bu::nanosecond); + /** unit of 1 microseccond = 10^-6 seconds **/ constexpr auto microsecond = su_from_bu(detail::bu::microsecond); + /** unit of 1 millisecond = 10^-3 seconds **/ constexpr auto millisecond = su_from_bu(detail::bu::millisecond); + /** unit of 1 second **/ constexpr auto second = su_from_bu(detail::bu::second); + /** unit of 1 minute **/ constexpr auto minute = su_from_bu(detail::bu::minute); + /** unit of 1 hour **/ constexpr auto hour = su_from_bu(detail::bu::hour); + /** unit for a 24-hour day **/ constexpr auto day = su_from_bu(detail::bu::day); + /** unit for a week comprising exactly 7 24-hour days **/ constexpr auto week = su_from_bu(detail::bu::week); + /** unit for a 30-day month **/ constexpr auto month = su_from_bu(detail::bu::month); + /** unit for a year containing exactly 365.25 24-hour days **/ constexpr auto year = su_from_bu(detail::bu::year); + /** unit for a 'year' containing exactly 250 24-hour days. + * (approximates the number of business days in a year) + **/ constexpr auto year250 = su_from_bu(detail::bu::year250); + /** unit for a 'year' containing exactly 360 24-hour days **/ constexpr auto year360 = su_from_bu(detail::bu::year360); + /** unit for a 'year' containing exactly 365 24-hour days **/ constexpr auto year365 = su_from_bu(detail::bu::year365); + ///@} + + /** @defgroup scaled-unit-misc scaled-unit miscellaneous units **/ + ///@{ + + // ----- currency ----- + + /** generic currency unit **/ + constexpr auto currency = su_from_bu(detail::bu::currency); + + // ----- price - --- + + /** generic price unit **/ + constexpr auto price = su_from_bu(detail::bu::price); + + ///@} + + // ----- volatility units ----- + + /** @defgroup scaled-unit-volatility scaled-unit volatility units **/ + ///@{ + + /** volatility, in 30-day units **/ constexpr auto volatility_30d = su_from_bu(detail::bu::month, power_ratio_type(-1,2)); + /** volatility, in 250-day 'annual' units **/ constexpr auto volatility_250d = su_from_bu(detail::bu::year250, power_ratio_type(-1,2)); + /** volatility, in 360-day 'annual' units **/ constexpr auto volatility_360d = su_from_bu(detail::bu::year360, power_ratio_type(-1,2)); + /** volatility, in 365-day 'annual' units **/ constexpr auto volatility_365d = su_from_bu(detail::bu::year365, power_ratio_type(-1,2)); + ///@} } namespace detail { @@ -197,6 +344,13 @@ namespace xo { } } + /** @defgroup scaled-unit-operators **/ + ///@{ + + /** Multiply scaled_unit instances @p x_unit and @p y_unit. + * Result is a scaled_unit for the product dimension. + * For each basis dimension, result will prioritize scale from @p x_unit ahead of @p y_unit. + **/ template > inline constexpr scaled_unit @@ -214,30 +368,10 @@ namespace xo { rr.outer_scale_sq_ * x_unit.outer_scale_sq_ * y_unit.outer_scale_sq_)); } -#ifdef OBSOLETE - template > - inline constexpr scaled_unit - operator* (const scaled_unit & x_unit, - const natural_unit & y_unit) - { - auto y_unit2 = detail::make_unit_rescale_result(y_unit); - - return x_unit * y_unit2; - } - - template > - inline constexpr scaled_unit - operator* (const natural_unit & x_unit, - const scaled_unit & y_unit) - { - auto x_unit2 = detail::make_unit_rescale_result(x_unit); - - return x_unit2 * y_unit; - } -#endif - + /** Divide scaled_unit instances @p x_unit by @p y_unit. + * Result is a scaled_unit for the quotient dimension. + * For each basis dimension, result will prioritize scale from @p x_unit ahead of @p y_unit. + **/ template > inline constexpr scaled_unit @@ -255,29 +389,7 @@ namespace xo { rr.outer_scale_sq_ * x_unit.outer_scale_sq_ * y_unit.outer_scale_sq_)); } -#ifdef OBSOLETE - template > - inline constexpr scaled_unit - operator/ (const scaled_unit & x_unit, - const natural_unit & y_unit) - { - auto y_unit2 = detail::make_unit_rescale_result(y_unit); - - return x_unit / y_unit2; - } - - template > - inline constexpr scaled_unit - operator/ (const natural_unit & x_unit, - const scaled_unit & y_unit) - { - auto x_unit2 = detail::make_unit_rescale_result(x_unit); - - return x_unit2 / y_unit; - } -#endif + ///@} } /*namespace qty*/ } /*namespace xo*/ diff --git a/include/xo/unit/xquantity.hpp b/include/xo/unit/xquantity.hpp index 31c9ef31..91fa74ce 100644 --- a/include/xo/unit/xquantity.hpp +++ b/include/xo/unit/xquantity.hpp @@ -48,6 +48,16 @@ namespace xo { constexpr xquantity(Repr scale, const natural_unit & unit) : scale_{scale}, unit_{unit} {} + constexpr xquantity(Repr scale, + const scaled_unit & unit) + : + scale_(scale + * unit.outer_scale_factor_.template convert_to() + * ((unit.outer_scale_sq_ == 1.0) + ? 1.0 + : ::sqrt(unit.outer_scale_sq_)) + ), + unit_{unit.natural_unit_} {} static constexpr bool always_constexpr_unit = false; diff --git a/utest/CMakeLists.txt b/utest/CMakeLists.txt index 5a063bc0..2ca38d03 100644 --- a/utest/CMakeLists.txt +++ b/utest/CMakeLists.txt @@ -12,13 +12,15 @@ set(SELF_SRCS unit.test.cpp #quantity.test.cpp ) -xo_add_utest_executable(${SELF_EXE} ${SELF_SRCS}) +if (ENABLE_TESTING) + xo_add_utest_executable(${SELF_EXE} ${SELF_SRCS}) -# ---------------------------------------------------------------- -# dependencies.. + # ---------------------------------------------------------------- + # dependencies.. -xo_self_dependency(${SELF_EXE} xo_unit) -xo_headeronly_dependency(${SELF_EXE} xo_ratio) -xo_external_target_dependency(${SELF_EXE} Catch2 Catch2::Catch2) + xo_self_dependency(${SELF_EXE} xo_unit) + xo_headeronly_dependency(${SELF_EXE} xo_ratio) + xo_external_target_dependency(${SELF_EXE} Catch2 Catch2::Catch2) +endif() # end CMakeLists.txt