xo-unit: kitchen-sink doc + build improvements + 1 bug fix

This commit is contained in:
Roland Conybeare 2024-05-22 15:16:17 -04:00
commit 412a0ba163
45 changed files with 1712 additions and 472 deletions

View file

@ -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
)

View file

@ -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 <xo/unit/basis_unit.hpp>
.. uml::
:scale: 99%
:align: center
:caption: basis unit representing 1 minute
object bu1<<basis_unit>>
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

View file

@ -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.

View file

@ -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-class>
basis-unit-constants

View file

@ -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

View file

@ -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

View file

@ -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:

View file

@ -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 <xo/unit/dimension.hpp>
Identifies an abstract dimension, for example *mass* or *time*.
For example can use this enum to index basis members of a :doc:`scaled_unit<scaled-unit-class>` instance:
.. code-block:: cpp
:emphasize-lines: 7-8
#include <xo/unit/quantity.hpp>
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

View file

@ -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 <iostream>
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<su::meter / (su::second * su::second)>(a);
constexpr auto t2 = t*t;
constexpr auto a = d / (t*t);
// 2.
constexpr auto a3 = a.rescale_ext<su::meter / (su::second * su::second)>();
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<u::meter / (u::second * u::second)>(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<u::meter / (u::second * u::second)>();
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<nu::second> t = q::minutes(2);
constexpr quantity<nu::meter> d = q::kilometers(2.5);
constexpr quantity<u::second> t = q::minutes(2);
constexpr quantity<u::meter> 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<nu::second, int>` to preserve
right-hand-side representation.
We could have instead used :code:`quantity<u::second, int>` 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 <iostream>
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<static_cast<double>(r1), double>);
// static_assert fails b/c static_cast only available for dimensionless quantity
//static_assert(std::same_as<decltype(static_cast<double>(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 <iostream>
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 <iostream>
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.

View file

@ -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<quantity-reference>`:
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<xquantity-reference>`:
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<scaled-unit-class>`:
.. 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<natural-unit-class>`
.. 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<bu-store-class>`
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<basis-unit-reference>`
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<dimension-enum>`
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<<quantity>>
qty1 : scale = 7.55
rectangle {
rectangle #e0f0ff {
object km_per_min2<<natural_unit>>
km_per_min2 : n_bpu = 2
@ -132,7 +194,7 @@ Worked example using :cpp:class:`xo::qty::quantity`
object qty2<<quantity>>
qty2 : scale = 123
rectangle {
rectangle #e0f0ff {
object ng_unit<<natural_unit>>
ng_unit : n_bpu = 1
@ -163,7 +225,7 @@ Worked example using :cpp:class:`xo::qty::quantity`
object qty3<<quantity>>
qty3 : scale = 928.65
rectangle {
rectangle #e0f0ff {
object ng_km_min2_unit<<natural_unit>>
ng_km_min2_unit : n_bpu = 3
@ -214,7 +276,7 @@ Worked example using :cpp:class:`xo::qty::quantity`
object qty3b<<quantity>>
qty3b : scale = 2.59758e-10
rectangle {
rectangle #e0f0ff {
object kg_m_s2_unit<<natural_unit>>
kg_m_s2_unit : n_bpu = 3

View file

@ -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
------------------

View file

@ -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

View file

@ -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 <xo/unit/natural_unit.hpp>
Representation for the unit associated with a @ref quantity or xquantity.
Representation for the unit associated with a :doc:`xquantity<xquantity-class>`
- 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<<natural_unit>>
newton : n_bpu = 3
newton : bpu_v[]
object kg<<bpu>>
kg : native_dim = dim::mass
kg : scalefactor = 1000/1
kg : power = 1/1
object m<<bpu>>
m : native_dim = dim::distance
m : scalefactor = 1/1
m : power = 1/1
object s2<<bpu>>
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

View file

@ -3,26 +3,70 @@
Quantity
========
.. ditaa::
+----------------+---------------+
|cYEL quantity | xquantity |
+----------------+---------------+
| scaled_unit |
+--------------------------------+
| natural_unit |
+--------------------------------+
| bpu |
+----------------+ |
| bu_store | |
+----------------+---------------+
| basis_unit |
+--------------------------------+
| dimension |
+--------------------------------+
.. code-block:: cpp
#include <xo/unit/quantity.hpp>
.. uml::
:scale: 99%
:align: center
allowmixing
object qty1<<quantity>>
qty1 : scale = 1.23
rectangle constexpr #e0f0ff {
object unit<<natural_unit>>
qty1 o-- unit : s_unit (static constexpr)
}
Arithmetic on :doc:`xo::qty::quantity<quantity-reference>` 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<Unit, Repr>``.
.. 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
------------

View file

@ -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

View file

@ -3,7 +3,13 @@
Scaled Unit
===========
A dimensionless multiple of a :doc:`natural_unit<natural-unit-class>`
Context
-------
.. ditaa::
:--scale: 0.85
+----------------+----------------+
| quantity | xquantity |
@ -21,15 +27,53 @@ Scaled Unit
| dimension |
+---------------------------------+
Introduction
------------
.. code-block::cpp
#include <xo/unit/scaled_unit.hpp>
Result of mutliplication or division of natural units (:doc:`natural-unit-class`).
Extension of :doc:`natural_unit<natural-unit-class>` 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<<scaled_unit>>
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<<natural_unit>>
m2_per_min : n_bpu = 2
m2_per_min : bpu_v[]
object m2<<bpu>>
m2 : native_dim = dim::distance
m2 : scalefactor = 1/1
m2 : power = 2/1
object min<<bpu>>
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<int64_t>(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<int64_t>(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<int64_t>(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

View file

@ -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 <xo/unit/quantity.hpp>
using namespace xo::qty;
constexpr quantity<u::meter / u::second> q1 = q::miles(60) / q::hour;
Note that it's often easiest to use :doc:`unit quantity constants<quantity-unitvars>`,
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

View file

@ -0,0 +1,31 @@
.. _scaled-unit-reference:
Scaled Unit Reference
=====================
A dimensionless multiple of a :doc:`natural_unit<natural-unit-class>`
.. 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-class>
scaled-unit-constants

View file

@ -1,12 +0,0 @@
.. _unit-concept:
Unit Concepts
=============
.. code-block:: cpp
#include <xo/unit/unit_concept.hpp>
.. doxygenconcept:: xo::unit::unit_concept
.. doxygenconcept:: xo::unit::basis_unit_concept

View file

@ -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 <typename Unit, typename Repr>
template <Quantity>
auto quantity<Unit, Repr>::with_units_from(Quantity q) {
return this->with_units<typename Quantity::unit_type>();
}
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<unit_cartesian_product_t<u::meter,
unit_invert_t<u::second>>>();
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<u::second>(); // q2 in km.s^-1
auto q3 = q2.with_basis_unit<u::meter>(); // 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.

View file

@ -1,10 +0,0 @@
.. _unit-reference:
Unit Reference
==============
.. toctree::
:maxdepth: 2
:caption: Unit Reference
unit-concept

15
docs/xquantity-class.rst Normal file
View file

@ -0,0 +1,15 @@
.. _xquantity-class:
Xquantity
=========
.. code-block:: cpp
#include <xo/unit/xquantity.hpp>
Class
-----
Class with run-time unit representation.
.. doxygenclass:: xo::qty::xquantity

View file

@ -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