diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index 99a1fdcc..bc00ca12 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -1,34 +1,41 @@ # xo-unit/docs/CMakeLists.txt -# copied from xo-observable/docs/CMakeLists.txt - -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) - -#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 -#file(GLOB_RECURSE SPHINX_RST_FILES ${CMAKE_CURRENT_SOURCE_DIR} *.rst) - -set(ALL_LIBRARY_TARGETS xo_unit) # todo: automate this from xo-cmake macros -#set(ALL_UTEST_TARGETS "") # todo: automate this from xo-cmake macros - -# look for doxygen executable -find_program(DOXYGEN_EXECUTABLE NAMES doxygen REQUIRED) -message("-- DOXYGEN_EXECUTABLE=${DOXYGEN_EXECUTABLE}") - if (XO_SUBMODULE_BUILD) # in submodule build, rely on toplevel docs/CMakeLists.txt file instead else() # build docs starting from here only in standalone build. # 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 + + # look for doxygen executable + find_program(DOXYGEN_EXECUTABLE NAMES doxygen REQUIRED) + message("-- DOXYGEN_EXECUTABLE=${DOXYGEN_EXECUTABLE}") + + # look for sphinx-build executable + find_program(SPHINX_EXECUTABLE NAMES sphinx-build REQUIRED) + message("-- SPHINX_EXECUTABLE=${SPHINX_EXECUTABLE}") + + 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) + + 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 + # + 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) + # TODO: # 1. move Doxyfile.in to xo-cmake project # 2. replace this command section with xo-cmake macro @@ -57,4 +64,34 @@ else() doxygen DEPENDS ${DOX_INDEX_FILE} ) + + # root of sphinx doc tree + set(SPHINX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}) + + add_custom_command( + OUTPUT ${SPHINX_INDEX_FILE} + DEPENDS doxygen conf.py ${SPHINX_RST_FILES} ${SPHINX_RST_FILES_GLOB} + COMMAND ${SPHINX_EXECUTABLE} + -b html -Dbreathe_projects.xodoxxml=${CMAKE_CURRENT_BINARY_DIR}/dox/xml + ${SPHINX_SOURCE} ${SPHINX_OUTPUT_DIR} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Generating docs (sphinx) -> [${SPHINX_OUTPUT_DIR}]") + + # make sphinx --> generate sphinx documentation + # + add_custom_target( + sphinx + DEPENDS ${SPHINX_INDEX_FILE}) + + # - html docs generated in build/docs/sphinx + # - copy the doc tree to share/doc/xo_unit/html + # + # OPTIONAL: install directory tree if it exists, + # but don't complain if it's missing + install( + DIRECTORY ${SPHINX_OUTPUT_DIR} + FILE_PERMISSIONS OWNER_READ GROUP_READ WORLD_READ + DESTINATION ${CMAKE_INSTALL_PREFIX}/share/doc/${PROJECT_NAME} + COMPONENT Documentation + OPTIONAL) endif() diff --git a/docs/examples.rst b/docs/examples.rst new file mode 100644 index 00000000..1aba11ed --- /dev/null +++ b/docs/examples.rst @@ -0,0 +1,117 @@ +.. _examples: + +.. toctree + :maxdepth: 2 + +Examples +======== + +Compile-time unit inference +--------------------------- + +.. code-block:: cpp + + #include "xo/unit/quantity.hpp" + #include + + int main() { + namespace u = xo::unit; + namespace qty = u::qty; + using namespace std; + + auto t = qty::milliseconds(10); + auto m = qty::kilograms(2.5); + auto a = m / (t * t); + + static_assert(same_as>); + static_assert(same_as>); + static_assert(sizeof(t) == sizeof(int)); + static_assert(sizeof(m) == sizeof(double)); + static_assert(sizeof(a) == sizeof(double)); + + cerr << "t: " << t << ", m: " << m << ", a: " << a << endl; + } + +with output: + +.. code-block:: + + t: 10ms, m: 2.5kg, m.t^-2: 0.025kg.ms^-2 + +Remarks: + +* The ``xo-unit`` system runs entirely at compile time; there's no runtime overhead. +* No runtime overhead includes construction of literal strings such as ``kg.ms^-2`` + (this is once place implementation requires c++20) +* Units are sticky: since we expressed ``t`` in milliseconds and ``m`` in kilograms, result is in the same terms. +* Unit ordering is sticky. Mass appears on the left in printed value of ``a`` because it was on the left-hand side of ``operator/`` +* Example omits verifying ``decltype(a)``, to keep output small. + +Scale conversion triggered by assignment +---------------------------------------- + +One way to convert units is by assignment: + +.. code-block:: cpp + :linenos: + :emphasize-lines: 9-10 + + #include "xo/unit/quantity.hpp" + #include + + int main() { + namespace u = xo::unit; + namespace qty = xo::units::qty; + using namespace std; + + quantity t = qty::milliseconds(10); + quantity m = qty::kilograms(2.5); + auto a = m / (t * t); + + cerr << "t: " << t << ", m: " << m << ", a: " << a << endl; + } + +with output: + +.. code-block:: + + t: 0.01s, m: 2500g, m.t^-2: 2.5e+07g.s^-2 + +Remarks: + +* Assignment to ``t`` converted to representation ``double``. + We could have used :code:`quantity` to convert (possibly rounding down) + representation to `int`. + +Scale conversion triggered by arithmetic +---------------------------------------- + +In representing a particular quantity, +xo-unit uses at most one scale for each :term:`basis dimension` associated with the unit for that quantity. +When an arithmetic operator encounters basis units involving two different scales, +the operator will adopt the scale provided by the left-hand argument: + +.. code-block:: cpp + :linenos: + :emphasize-lines: 11 + + #include "xo/unit/quantity.hpp" + #include + + int main() { + namespace u = xo::unit; + namespace qty = xo::units::qty; + using namespace std; + + auto t1 = qty::milliseconds(1); + auto t2 = qty::minutes(1); + auto p = t1 * t2; + + cerr << "t1: " << t1 << ", t2: " << t2 << ", p: " << p << endl; + } + +with output: + +.. code-block:: + + t1: 1ms, t2: 1min, t1*t2: 60000ms^2 diff --git a/docs/glossary.rst b/docs/glossary.rst new file mode 100644 index 00000000..5d594f81 --- /dev/null +++ b/docs/glossary.rst @@ -0,0 +1,26 @@ +.. _glossary: + +Glossary +-------- + +.. glossary:: + basis dimension + Orthogonal directions associated with basis units, for example *mass*, *length*, *time*. + In xo-unit these are represented by the enum ``xo::unit::dim``. + + basis unit + An implementation type representing a quantity (with associated scale) in the direction of a single :term:`basis dimension`. + For example *milliseconds*, *seconds*, and *hours* stand for different basis units with the *time* dimension. + In xo-unit these are represented by the template type ``xo::unit::basis_unit``. + + bpu + A rational power of a (single) basis unit. For example *kg.m.s\ :sup:-2* or *hr\ :sup:-(1/2)*. + In xo-unit these are represented by the template type ``xo::unit::bpu``. + + XO + A set of integrated c++ libraries for complex event processing, with browser and python integration. + `xo documentation here`_ + +.. _xo documentation here: https://rconybea.github.io/web/sw/xo.html + +.. toctree:: diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 00000000..108d97d4 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,40 @@ +.. xo-unit-examples documentation master file, created by + sphinx-quickstart on Wed Mar 6 23:32:27 2024. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +xo-unit documentation +===================== + +xo-unit is a lightweight header-only library that provides compile-time +dimension checking and unit conversion. + +Functionality is similar in spirit to that provided by ``boost::units``; +however there are some important differences: + +First, implementation relies on c++20 features +like class-instance template parameters to efficiently assemble string constants at compile time. + +Second, ``xo-unit`` supports fractional dimensions. This allows using it to naturally handle +concepts like volatility (dimension 1/sqrt(time)), for example. + +Finally, ``xo-unit`` is written with the expectation of providing +python integration via pybind11. This requires a parallel set of data structures that can work at +runtime (since we can't construct new c++ types at runtime). + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + install + examples + classes + +Indices and Tables +------------------ + +* :ref:`glossary` +* :ref:`genindex` +* :ref:`search` + +.. toctree:: diff --git a/docs/install.rst b/docs/install.rst new file mode 100644 index 00000000..d8e0f9bd --- /dev/null +++ b/docs/install.rst @@ -0,0 +1,62 @@ +.. _install: + +.. toctree + :maxdepth: 2 + +Install +======= + +`xo-unit source`_ lives on github. + +.. _xo-unit source: https://github.com/rconybea/xo-unit + +Implementation relies on some c++20 features (for example class-instances as template arguments). +Tested with gcc 12.3 + +Include as submodule +-------------------- + +.. code-block:: bash + + cd myproject + 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, +and add + +.. code-block:: c++ + + #include + +to c++ source files that rely on xo-unit + +Supported compilers +------------------- + +* developed with gcc 12.3.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