xo-unit: docs: cmakefile deps ++ cover quantity features

This commit is contained in:
Roland Conybeare 2024-04-05 01:45:17 -04:00
commit c25930b7f5
12 changed files with 296 additions and 26 deletions

View file

@ -7,7 +7,7 @@ else()
# otherwise use top-level doxygen setup instead.
set(ALL_LIBRARY_TARGETS xo_unit) # todo: automate this from xo-cmake macros
set(ALL_UTEST_TARGETS utest.unit) # todo: automate this from xo-cmake macros
set(ALL_UTEST_TARGETS utest.unit xo_unit_ex1 xo_unit_ex2 xo_unit_ex3 xo_unit_ex4 xo_unit_ex5 xo_unit_ex6) # todo: automate this from xo-cmake macros
# look for doxygen executable
find_program(DOXYGEN_EXECUTABLE NAMES doxygen REQUIRED)
@ -19,22 +19,27 @@ else()
set(DOX_CONFIG_FILE ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
#set(DOX_DEPS ${PROJECT_SOURCE_DIR}/mainpage.dox) # not yet
set(DOX_INPUT_DIR ${PROJECT_SOURCE_DIR})
set(DOX_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/dox)
set(DOX_INDEX_FILE ${DOX_OUTPUT_DIR}/html/index.html)
# .hpp files reachable from xo-unit/include
#
# REMINDER: for reliability will need to re-run cmake when the set of .hpp files changes
#
file(GLOB_RECURSE DOX_HPP_FILES_GLOB ${PROJECT_SOURCE_DIR}/include *.hpp)
set(SPHINX_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/sphinx/html)
set(SPHINX_INDEX_FILE ${SPHINX_OUTPUT_DIR}/index.html)
#
# sphinx .rst files reachable from cmake-examples/docs
#
# REMINDER: will need to re-run cmake when the set of .rst files changes
# REMINDER: for reliability will need to re-run cmake when the set of .rst files changes
#
file(GLOB_RECURSE SPHINX_RST_FILES_GLOB ${CMAKE_CURRENT_SOURCE_DIR} *.rst)
set(SPHINX_RST_FILES index.rst install.rst examples.rst classes.rst glossary.rst)
set(SPHINX_RST_FILES index.rst install.rst examples.rst unit-quantities.rst quantity-class.rst quantity-factoryfunctions.rst quantity-unitvars.rst unit-reference.rst unit-concept.rst glossary.rst)
# TODO:
# 1. move Doxyfile.in to xo-cmake project
@ -45,10 +50,12 @@ else()
FILE_PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
@ONLY)
set(DOX_DEPS ${ALL_LIBRARY_TARGETS} ${ALL_UTEST_TARGETS} ${DOX_HPP_FILES_GLOB})
file(MAKE_DIRECTORY ${DOX_OUTPUT_DIR})
add_custom_command(
OUTPUT ${DOX_INDEX_FILE}
DEPENDS ${DOX_DEPS} ${ALL_LIBRARY_TARGETS} ${ALL_UTEST_TARGETS}
DEPENDS ${DOX_DEPS}
COMMAND "${DOXYGEN_EXECUTABLE}" ${DOX_CONFIG_FILE}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
MAIN_DEPENDENCY ${DOX_CONFIG_FILE}
@ -62,15 +69,16 @@ else()
#
add_custom_target(
doxygen
DEPENDS ${DOX_INDEX_FILE}
DEPENDS ${DOX_INDEX_FILE} ${DOX_DEPS}
)
# root of sphinx doc tree
set(SPHINX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR})
set(SPHINX_DEPS doxygen conf.py ${SPHINX_RST_FILES} ${SPHINX_RST_FILES_GLOB} ${DOX_DEPS})
add_custom_command(
OUTPUT ${SPHINX_INDEX_FILE}
DEPENDS doxygen conf.py ${SPHINX_RST_FILES} ${SPHINX_RST_FILES_GLOB}
DEPENDS ${SPHINX_DEPS}
COMMAND ${SPHINX_EXECUTABLE}
-b html -Dbreathe_projects.xodoxxml=${CMAKE_CURRENT_BINARY_DIR}/dox/xml
${SPHINX_SOURCE} ${SPHINX_OUTPUT_DIR}

View file

@ -3,6 +3,7 @@ map
index.rst
+- install.rst
+- examples.rst
+- unit-quantities.rst
+- classes.rst
+- glossary.rst

View file

@ -1,10 +0,0 @@
.. _classes:
.. toctree
:maxdepth: 2
Template Classes
================
.. doxygenclass:: xo::unit::quantity
:members:

View file

@ -15,16 +15,17 @@ Compile-time unit inference
#include <iostream>
int main() {
namespace u = xo::unit;
namespace qty = u::qty;
namespace u = xo::unit::units;
namespace qty = xo::unit::qty;
using xo::unit::quantity;
using namespace std;
auto t = qty::milliseconds(10);
auto m = qty::kilograms(2.5);
auto a = m / (t * t);
static_assert(same_as<decltype(t), u::quantity<u::millisecond, int>>);
static_assert(same_as<decltype(m), u::quantity<u::kilogram, double>>);
static_assert(same_as<decltype(t), quantity<u::millisecond, int>>);
static_assert(same_as<decltype(m), quantity<u::kilogram, double>>);
static_assert(sizeof(t) == sizeof(int));
static_assert(sizeof(m) == sizeof(double));
static_assert(sizeof(a) == sizeof(double));
@ -88,7 +89,7 @@ One way to convert units is by assignment:
.. code-block:: cpp
:linenos:
:emphasize-lines: 9-10
:emphasize-lines: 10-11
#include "xo/unit/quantity.hpp"
#include <iostream>
@ -96,6 +97,7 @@ One way to convert units is by assignment:
int main() {
namespace u = xo::unit;
namespace qty = xo::units::qty;
using xo::unit::quantity;
using namespace std;
quantity<units::second> t = qty::milliseconds(10);

View file

@ -24,11 +24,13 @@ runtime (since we can't construct new c++ types at runtime).
.. toctree::
:maxdepth: 2
:caption: Contents:
:caption: xo-unit contents:
install
examples
classes
unit-quantities
quantity-reference
unit-reference
Indices and Tables
------------------
@ -36,5 +38,3 @@ Indices and Tables
* :ref:`glossary`
* :ref:`genindex`
* :ref:`search`
.. toctree::

70
docs/quantity-class.rst Normal file
View file

@ -0,0 +1,70 @@
.. _quantity-class:
Quantity
========
.. code-block:: cpp
#include <xo/unit/quantity.hpp>
The primary data structure for interacting with xo-unit is the
template class ``xo::unit::quantity``.
.. doxygenclass:: xo::unit::quantity
Type Traits
-----------
.. doxygengroup:: quantity-traits
:content-only:
Constructors
------------
.. doxygengroup:: quantity-ctors
:content-only:
.. doxygengroup:: quantity-named-ctors
:content-only:
The simplest way to create a quantity instance is to use either
* factory functions in ``xo::unit::qty``, see :doc:`quantity-factoryfunctions`
* unit variables in ``xo::unit::units``, see :doc:`quantity-unitvars`
Access Methods
--------------
.. doxygengroup:: quantity-access-methods
:content-only:
Constants
---------
.. doxygengroup:: quantity-constants
:content-only:
Conversion Methods
------------------
Amount-preserving conversion to quantities with different units and/or representation.
.. doxygengroup:: quantity-unit-conversion
:content-only:
Arithmetic
----------
.. doxygengroup:: quantity-arithmetic
:content-only:
Support methods for arithmetic operations
.. doxygengroup:: quantity-arithmeticsupport
:content-only:
Assignment
----------
.. doxygengroup:: quantity-assignment
:content-only:

View file

@ -0,0 +1,27 @@
.. _quantity_factoryfunctions:
.. toctree::
:maxdepth: 2
Quantity Factory Functions
==========================
.. code-block:: cpp
#include <xo/unit/quantity.hpp>
.. doxygenfunction:: xo::unit::qty::milligrams
.. doxygenfunction:: xo::unit::qty::grams
.. doxygenfunction:: xo::unit::qty::kilograms
.. doxygenfunction:: xo::unit::qty::millimeters
.. doxygenfunction:: xo::unit::qty::meters
.. doxygenfunction:: xo::unit::qty::kilometers
.. doxygenfunction:: xo::unit::qty::nanoseconds
.. doxygenfunction:: xo::unit::qty::microseconds
.. doxygenfunction:: xo::unit::qty::milliseconds
.. doxygenfunction:: xo::unit::qty::seconds
.. doxygenfunction:: xo::unit::qty::minutes
.. doxygenfunction:: xo::unit::qty::hours
.. doxygenfunction:: xo::unit::qty::days

View file

@ -0,0 +1,12 @@
.. _quantity-reference:
Quantity Reference
==================
.. toctree::
:maxdepth: 2
:caption: Quantity Reference
quantity-class
quantity-factoryfunctions
quantity-unitvars

View file

@ -0,0 +1,45 @@
.. _quantity-unitvars:
.. toctree::
:maxdepth: 2
Quantity Unit Variables
=======================
.. code-block:: cpp
#include <xo/unit/quantity.hpp>
The ``xo::unit::unit_qty`` namespace contains unit quantities in each dimension.
Can use these to request unit conversion involving multiple dimensions, for example:
.. code-block:: cpp
namespace qty = xo::unit::qty;
namespace u = xo::unit::unit_qty;
auto q1 = (qty::kilometers(150.0) / qty::hours(0.5);
auto q2 = q1.with_units_from(u:meter / u:second);
Mass
----
.. doxygenvariable:: xo::unit::unit_qty::milligram
.. doxygenvariable:: xo::unit::unit_qty::gram
.. doxygenvariable:: xo::unit::unit_qty::kilogram
Distance
--------
.. doxygenvariable:: xo::unit::unit_qty::millimeter
.. doxygenvariable:: xo::unit::unit_qty::meter
.. doxygenvariable:: xo::unit::unit_qty::kilometer
Time
----
.. doxygenvariable:: xo::unit::unit_qty::nanosecond
.. doxygenvariable:: xo::unit::unit_qty::microsecond
.. doxygenvariable:: xo::unit::unit_qty::millisecond
.. doxygenvariable:: xo::unit::unit_qty::second
.. doxygenvariable:: xo::unit::unit_qty::minute
.. doxygenvariable:: xo::unit::unit_qty::hour
.. doxygenvariable:: xo::unit::unit_qty::day

12
docs/unit-concept.rst Normal file
View file

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

93
docs/unit-quantities.rst Normal file
View file

@ -0,0 +1,93 @@
.. _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.

10
docs/unit-reference.rst Normal file
View file

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