docs: initial V2 documenatation added

This commit is contained in:
Mateusz Pusz
2023-06-21 10:55:18 +02:00
parent dde5bcab7e
commit 4b3e31f40d
236 changed files with 1495 additions and 7967 deletions

View File

@ -24,79 +24,29 @@ name: Documentation
on:
push:
paths:
- ".github/workflows/documentation.yml"
- "docs/**"
- "src/**"
- "example/**"
pull_request:
paths:
- ".github/workflows/documentation.yml"
- "docs/**"
- "src/**"
- "example/**"
branches:
- master
- main
permissions:
contents: write
jobs:
docs:
name: Generate documentation
runs-on: ${{ matrix.os }}
env:
CC: gcc-10
CXX: g++-10
CMAKE_GENERATOR: Ninja
CONAN_CMAKE_GENERATOR: Ninja
OS: ubuntu-22.04
BUILD_TYPE: Debug
COMPILER_TYPE: GCC
COMPILER_VERSION: 10
STDLIB: libstdc++11
strategy:
fail-fast: false
matrix:
os: ["ubuntu-latest"]
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Cache Conan data
uses: actions/cache@v3
env:
cache-name: cache-conan-data
- uses: actions/setup-python@v4
with:
path: ~/.conan2/p
key: build-${{ matrix.os }}-$BUILD_TYPE-$COMPILER_TYPE-$COMPILER_VERSION-$STDLIB-docs
python-version: 3.x
- run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
- uses: actions/cache@v3
with:
key: mkdocs-material-${{ env.cache_id }}
path: .cache
restore-keys: |
build-${{ matrix.os }}-$BUILD_TYPE-$COMPILER_TYPE-$COMPILER_VERSION-$STDLIB
build-${{ matrix.os }}-$BUILD_TYPE-$COMPILER_TYPE-$COMPILER_VERSION-
build-${{ matrix.os }}-$BUILD_TYPE-$COMPILER_TYPE-
build-${{ matrix.os }}-$BUILD_TYPE-
build-${{ matrix.os }}-
- name: Install Ninja
mkdocs-material-
- name: Installing pip packages
run: |
sudo apt install -y ninja-build
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.8"
- name: Install Python dependencies
pip install conan mkdocs-material mike
- name: Building docs
run: |
pip install -Ur docs/requirements.txt
- name: Install Conan
run: |
pip install -U conan
- name: Configure Conan
run: |
conan profile detect --force
conan remote add artifactory https://mpusz.jfrog.io/artifactory/api/conan/conan-oss
- name: Install Conan dependencies
run: |
conan install . -s compiler.cppstd=20 -s compiler.libcxx=$STDLIB -c user.build:all=True -c tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" -b missing
- name: Configure CMake
run: |
cmake --preset conan-default
- name: Generate documentation
run: |
cmake --build --preset conan-release --target documentation
- name: Deploy documentation
if: github.ref == 'refs/heads/master'
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./build/docs/sphinx
mike deploy --push --update-aliases `conan inspect . | sed -n -r 's/version: ([0-9]+.[0-9]+).[0-9]+/\1/p'` latest

View File

@ -25,7 +25,7 @@ project(mp-units-dev LANGUAGES CXX)
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
set(projectPrefix UNITS_)
set(projectPrefix MP_UNITS_)
option(${projectPrefix}BUILD_LA "Build code depending on the linear algebra library" ON)
message(STATUS "${projectPrefix}BUILD_LA: ${${projectPrefix}BUILD_LA}")
@ -70,9 +70,6 @@ add_subdirectory(src)
# add usage example
add_subdirectory(example)
# generate project documentation
# add_subdirectory(docs)
# add unit tests
enable_testing()

View File

@ -25,8 +25,8 @@ enable the rest of mainstream compilers and update the documentation to reflect
## Documentation
An extensive project documentation for the previous release library version can be found on
[mp-units GitHub Pages](https://mpusz.github.io/mp-units). It includes installation instructions and user's guide.
An extensive project documentation can be found on [mp-units GitHub Pages](https://mpusz.github.io/mp-units).
It includes installation instructions and a detailed user's guide.
## Terms and Definitions
@ -100,8 +100,8 @@ int main()
constexpr auto v1 = 110 * (km / h);
constexpr auto v2 = 70 * mph;
constexpr auto v3 = avg_speed(220. * km, 2 * h);
constexpr auto v4 = avg_speed(isq::distance(140. * mi), 2 * isq::duration[h]);
constexpr auto v3 = avg_speed(220. * isq::distance[km], 2 * h);
constexpr auto v4 = avg_speed(isq::distance(140. * mi), 2 * h);
constexpr auto v5 = v3[m / s];
constexpr auto v6 = value_cast<m / s>(v4);
constexpr auto v7 = value_cast<int>(v6);
@ -116,4 +116,4 @@ int main()
}
```
_Try it on the [Compiler Explorer](https://godbolt.org/z/rrTojn47v)._
_Try it on the [Compiler Explorer](https://godbolt.org/z/T8bovrqTP)._

View File

@ -1,7 +0,0 @@
# Look for an executable called sphinx-build
find_program(SPHINX_EXECUTABLE NAMES sphinx-build DOC "Path to sphinx-build executable")
include(FindPackageHandleStandardArgs)
# Handle standard arguments to find_package like REQUIRED and QUIET
find_package_handle_standard_args(Sphinx "Failed to find sphinx-build executable" SPHINX_EXECUTABLE)

View File

@ -1,123 +0,0 @@
# The MIT License (MIT)
#
# Copyright (c) 2018 Mateusz Pusz
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
cmake_minimum_required(VERSION 3.5)
# TODO Switch to CONFIG when Conan will start supporting imported executables in CMakeDeps
find_package(Doxygen MODULE REQUIRED)
find_package(Sphinx REQUIRED)
#
# add_documentation(TargetName [ALL]
# BREATHE_PROJECT projectName
# [DOXYFILE_TEMPLATE Doxyfile.in]
# [CODE_SOURCE_DIR dir]
# [DOCS_SOURCE_DIR dir]
# [INSTALL_DIR dir]
# CODE_DEPENDS codeDeps...
# DOC_DEPENDS docDeps...)
#
function(add_documentation targetName)
set(_options ALL)
set(_one_value_args BREATHE_PROJECT DOXYFILE_TEMPLATE CODE_SOURCE_DIR DOCS_SOURCE_DIR INSTALL_DIR)
set(_multi_value_args CODE_DEPENDS DOCS_DEPENDS)
cmake_parse_arguments(_args "${_options}" "${_one_value_args}" "${_multi_value_args}" ${ARGN})
if(NOT _args_BREATHE_PROJECT)
message(FATAL_ERROR "BREATHE_PROJECT not provided")
endif()
# Validate arguments
if(NOT _args_DOXYFILE_TEMPLATE)
set(_args_DOXYFILE_TEMPLATE Doxyfile.in)
endif()
get_filename_component(_doxyfileIn ${_args_DOXYFILE_TEMPLATE} REALPATH)
if(NOT EXISTS ${_doxyfileIn})
message(FATAL_ERROR "'${_args_DOXYFILE_TEMPLATE}' does not exist")
endif()
if(_args_DOCS_SOURCE_DIR)
if(NOT EXISTS ${_args_DOCS_SOURCE_DIR})
message(FATAL_ERROR "'${_args_DOCS_SOURCE_DIR}' does not exist")
endif()
else()
set(_args_DOCS_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
endif()
# Validate CODE_SOURCE_DIR and set input for the configuration file
if(_args_CODE_SOURCE_DIR)
if(NOT EXISTS ${_args_CODE_SOURCE_DIR})
message(FATAL_ERROR "'${_args_CODE_SOURCE_DIR}' does not exist")
endif()
set(DOXYGEN_INPUT_DIR "${_args_CODE_SOURCE_DIR}")
else()
set(DOXYGEN_INPUT_DIR "${PROJECT_SOURCE_DIR}")
endif()
set(DOXYGEN_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/doxygen")
# Replace variables inside @@ with the current values
set(_doxyfile "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile")
configure_file("${_doxyfileIn}" "${_doxyfile}" @ONLY)
set(_doxygenIndexFile "${DOXYGEN_OUTPUT_DIR}/xml/index.xml")
# Only regenerate Doxygen when the Doxyfile or given dependencies change
add_custom_command(
OUTPUT "${_doxygenIndexFile}"
COMMAND ${CMAKE_COMMAND} -E make_directory ${DOXYGEN_OUTPUT_DIR}
COMMAND Doxygen::doxygen ARGS "${_doxyfile}"
MAIN_DEPENDENCY "${_doxyfileIn}"
DEPENDS "${_doxyfile}" "${_args_CODE_DEPENDS}"
COMMENT "Generating doxygen XML metadata"
USES_TERMINAL VERBATIM
)
set(_sphinx_docs_dir "${CMAKE_CURRENT_BINARY_DIR}/sphinx")
set(_sphinx_index_file "${_sphinx_docs_dir}/index.html")
# Only regenerate Sphinx when:
# - Doxygen has rerun
# - Our doc files have been updated
# - The Sphinx config has been updated
add_custom_command(
OUTPUT "${_sphinx_index_file}"
COMMAND "${SPHINX_EXECUTABLE}" ARGS -b html -j auto
"-Dbreathe_projects.${_args_BREATHE_PROJECT}=${DOXYGEN_OUTPUT_DIR}/xml" "${_args_DOCS_SOURCE_DIR}"
"${_sphinx_docs_dir}"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
MAIN_DEPENDENCY "${_args_DOCS_SOURCE_DIR}/conf.py"
DEPENDS "${_doxygenIndexFile}" "${_args_DOCS_DEPENDS}"
COMMENT "Generating documentation with Sphinx"
USES_TERMINAL VERBATIM
)
# Custom target
if(_args_ALL)
set(_all ALL)
endif()
add_custom_target(${targetName} ${_all} DEPENDS "${_sphinx_index_file}")
if(_args_INSTALL_DIR)
# Add an install step to install the docs
install(DIRECTORY ${_sphinx_docs_dir} TYPE DOC)
endif()
endfunction()

View File

@ -82,10 +82,6 @@ class MPUnitsConan(ConanFile):
def _skip_la(self):
return bool(self.conf.get("user.build:skip_la", default=False))
@property
def _skip_docs(self):
return bool(self.conf.get("user.build:skip_docs", default=True))
@property
def _use_libfmt(self):
compiler = self.settings.compiler
@ -118,8 +114,6 @@ class MPUnitsConan(ConanFile):
self.test_requires("catch2/3.3.2")
if not self._skip_la:
self.test_requires("wg21-linear_algebra/0.7.3")
if not self._skip_docs:
self.tool_requires("doxygen/1.9.4")
def validate(self):
check_min_cppstd(self, self._min_cppstd)

View File

@ -0,0 +1,8 @@
{% extends "base.html" %}
{% block outdated %}
You're not viewing the latest version.
<a href="{{ '../' ~ base_url }}">
<strong>Click here to go to latest.</strong>
</a>
{% endblock %}

View File

@ -1,241 +0,0 @@
# Release notes
- **2.0.0 WIP**
- `units` namespace renamed to `mp_units` (#317)
- header files in the `<mp-units/...>` rather then in `<units/...>` (#317)
- the downcasting facility is removed (#383, #211, #32)
- unified and simplified quantity creation (#274)
- Determining the best way to create a quantity (#413)
- V2 quantity_point (#414)
- introduction of `quantity_spec` to store not only `dimension` but also additional information about quantities (#405)
- `quantity` now takes `reference` object, which aggregates `quantity_spec` and a `unit` and a `representation` type
- units, prefixes, dimensions, quantity specifications, and references are passed as NTTPs to templates and provide arithmetic operations and comparison
- expression templates consistently used in all derived types to increase the readability (#351, #166)
- derived dimensions are now factors of only base dimensions (#281)
- Interconvertibility of derived quantities (#427)
- dimensions, quantity specifications, units, and references are now composable, significantly reducing the number of definitions and resulting types
- heavily simplified unit systems definitions (no need to define unnamed derived units, systems-specific dimensions, aliases for quantities, concepts, UDLs, ... anymore)
- improved definition of all systems
- support for all (or at least most) ISO 80000 quantities
- faster than lightspeed constants (#169)
- extensions to quantity formatting with `fmt`
- `quantity_kind` removed
- much easier and safe casting of unit with `operator[]` and `.number_in(Unit)`
- quantity can no longer be constructed with a raw value (#434)
- Implicit construction of quantities from a value (#410)
- `ceil` and `floor` are dangerous (#432)
- quecto, ronto, ronna, quetta new SI prefixes support
- many smaller changes not possible to address with the previous design (#205, #210, #134)
- **0.8.0 June 14, 2023**
- (!) refactor: `common_quantity`, `common_quantity_for`, `common_quantity_point`, `common_quantity_kind`, and `common_quantity_point_kind` removed
- (!) refactor: `named_derived_unit` removed as it was not used
- (!) refactor: `derived_unit` renamed to `derived_scaled_unit`
- (!) refactor: `unit` renamed to `derived_unit`
- (!) refactor: `U::is_named` removed from the unit types and replaced with `NamedUnit` concept
- (!) refactor: `PrefixFamily` support removed
- (!) refactor: `mi(naut)` renamed to `nmi`
- (!) refactor: `knot` unit helper renamed to `kn` in FPS
- (!) refactor: `knot` text symbol changed from `"knot"` to `"kn"`
- refactor: `quantity` `op+()` and `op-()` reimplemented in terms of `reference` rather then `quantity` types
- refactor(example): `glide_computer` now use dimensionless quantities with `ranged_representation` as `rep`
- feat: HEP system support added (thanks [@RalphSteinhagen](https://github.com/RalphSteinhagen))
- feat: `floor()`, `ceil()`, and `round()` support added (thanks [@hofbi](https://github.com/hofbi))
- feat: `std::format` support for compliant compilers added
- feat: conversion helpers from `mp-units` to `std::chrono` types added
- feat: math functions can now be safely used with user-defined types
- feat: conversion from `quantity_point` to `std::chrono::time_point` added
- feat: `nautical_mile_per_hour` and `knot` added to `si::international` system
- (!) fix: add `quantity_point::origin`, like `std::chrono::time_point::clock`
- fix: enable any prefixes for most of the named units (beside those that use prefixes already)
- fix: `hectare` definition fixed to be a prefixed version of `are` + other units
- fix: account for different dimensions in `quantity_point_cast`'s constraint
- fix: output stream operator now properly handles state
- fix: `fmt` algorithms were overconstrained with `forward_iterator`
- fix: CTAD for aliases fixed
- fix: `derived_ratio` calculation
- fix: `fill_t` assignment operator fixed
- fix: improve downcast mode off
- fix: `radioactivity` header compilation fixed
- fix: `si::hep::dim_momentum` duplicated definition fixed
- fix: `fps` can now coexist with `international` system
- fix: public headers fixed to be standalone
- test: standalone public headers tests added
- (!) build: CMake generator in Conan is no longer obtained from an environment variable
- (!) build: Required Conan version bumped to 1.48
- (!) build: Conan 1.48 does not set `CMAKE_BUILD_TYPE` in the `conan_toolchain.cmake` anymore
- build: AppleClang 13 support added (thanks [@fdischner](https://github.com/fdischner))
- build: most of the `conanfile.py` refactored to be Conan 2.0 ready
- build: `validate()` replaced with `configure()` to raise errors during `conan install` in Conan 1.X
- build: minimum Conan version changed to 1.40
- build: `linear-algebra` Conan repo is no needed anymore
- build: Gitpod support added
- build: clang-format-15 support added
- build: export config to local build (#322)
- build: fix export name of `mp-units-system`
- build: fmt updated to 8.0.1
- build: gsl-lite updated to 0.40.0
- build: catch2 updated to 2.13.9
- build: doxygen updated to 1.9.4
- build: linear_algebra/0.7.0 switched to wg21-linear_algebra/0.7.2
- ci: VS2022, gcc-11, clang-13, clang-14, and AppleClang 13 support added
- ci: pre-commit support added (thanks [@hofbi](https://github.com/hofbi))
- docs: Project documentation updated
- docs: `CITATION.cff` file added
- docs: `CONTRIBUTING.md` updated
- **0.7.0 May 11, 2021**
- (!) refactor: `ScalableNumber` renamed to `Representation`
- (!) refactor: output stream operators moved to the `units/quantity_io.h` header file
- (!) refactor: Refactored the library file tree
- (!) refactor: `quantity::count()` renamed to `quantity::number()`
- (!) refactor: `data` system renamed to `isq::iec80000` (quantity names renamed too)
- (!) refactor: `*deduced_unit` renamed to `*derived_unit`
- (!) refactor: got rid of a `noble_derived_unit`
- refactor: quantity (kind) point updated to reflect latest changes to `quantity`
- refactor: basic concepts, `quantity` and `quantity_cast` refactored
- refactor: `abs()` definition refactored to be more explicit about the return type
- feat: quantity (point) kind support added (thanks [@johelegp](https://github.com/johelegp))
- feat: quantity references support added (thanks [@johelegp](https://github.com/johelegp))
- feat: quantity aliases support addded
- feat: interoperability with `std::chrono::duration` and other units libraries
- feat: CTAD for dimensionless quantity added
- feat: `modulation_rate` support added (thanks [@go2sh](https://github.com/go2sh))
- feat: SI prefixes for `isq::iec80000` support added (thanks [@go2sh](https://github.com/go2sh))
- feat: a possibility to disable quantity UDLs support with `UNITS_NO_LITERALS` preprocessor define
- feat: a support to define ISQ derived dimensions in terms of different number or order of components
- perf: preconditions check do not influence the runtime performance of a Release build
- perf: `quantity_cast()` generates less assembly instructions
- perf: temporary string creation removed from `quantity::op<<()`
- perf: value initialization for quantity value removed (left with a default initialization)
- perf: limited the `equivalent` trait usage
- perf: limited the C++ Standard Library headers usage
- perf: rvalue references support added for constructors and getters
- (!) fix: `exp()` has sense only for dimensionless quantities
- (!) fix: `dim_torque` now properly divides by an angle (instead of multiply) + default unit name change
- fix: quantity's operators fixed to behave like the underlying types do
- fix: `quantity_cast()` fixed to work correctly with representation types not convertible from `std::intmax_t`
- fix: ambiguous case for empty type list resolved
- fix: downcasting facility for non-default-constructible types
- fix: restore user-warnings within the library implementation
- fix: the text symbol of `foot_pound_force` and `foot_pound_force_per_second`
- fix: quantity modulo arithmetics fixed
- (!) build: Conan testing version is now hosted on [Artifactory](https://mpusz.jfrog.io/ui/packages/conan:%2F%2Fmp-units)
- (!) build: Linear Algebra is now hosted on its [Artifactory](https://twonington.jfrog.io/artifactory/api/conan/conan-oss)
- (!) build: `BUILD_DOCS` CMake option renamed to `UNITS_BUILD_DOCS`
- build: doxygen updated to 1.8.20
- build: catch2 updated to 2.13.4
- build: fmt updated to 7.1.3
- build: ms-gsl replaced with gsl-lite/0.38.0
- build: Conan generator switched to `cmake_find_package_multi`
- build: Conan CMakeToolchain support added
- build: CMake scripts cleanup
- build: ccache support added
- ci: CI switched from Travis CI to GitHub Actions
- **0.6.0 September 13, 2020**
- feat: `quantity_point` support added (thanks [@johelegp](https://github.com/johelegp))
- feat: Added angle as SI base dimension (thanks [@kwikius](https://github.com/kwikius))
- feat: `si::angular_velocity` support added (thanks [@mikeford3](https://github.com/mikeford3))
- feat: FPS system added (thanks [@mikeford3](https://github.com/mikeford3))
- feat: Added support for mathematical function `exp(quantity)`
- feat: Localization support for text output added (thanks [@rbrugo](https://github.com/rbrugo))
- feat: Added STL random number distribution wrappers (thanks [@yasamoka](https://github.com/yasamoka))
- (!) refactor: Refactored and cleaned up the library file tree
- (!) refactor: `q_*` UDL renamed to `_q_*`
- (!) refactor: UDLs with "per" in name renamed from `*p*` to `*_per_*`
- (!) refactor: `ratio` changed to the NTTP kind
- (!) refactor: `exp` and `Exp` renamed to `exponent` and `Exponent`
- (!) refactor: `Scalar` concept renamed to `ScalableNumber`
- (!) refactor: Dimensionless quantities redesigned to be of a `quantity` type
- refactor: `math.h` function signatures refactored to use a `Quantity` concept (thanks [@kwikius](https://github.com/kwikius))
- refactor: `[[nodiscard]]` added to many functions
- fix: `si::day` unit symbol fixed to `d` (thanks [@komputerwiz](https://github.com/komputerwiz))
- fix: `si::mole` unit symbol fixed to `mol` (thanks [@mikeford3](https://github.com/mikeford3))
- (!) build: gcc-9 is no longer supported (at least gcc-10 is required)
- build: Visual Studio 16.7 support added
- build: linear_algebra updated to 0.7.0/stable
- build: fmt updated to 7.0.3
- build: range-v3 updated to 0.11.0
- build: catch2 updated to 2.13.0
- build: doxygen updated to 1.8.18
- build: ms-gsl 3.1.0 dependency added
- build: Removed the dependency on a git submodule with common CMake scripts
- **0.5.0 May 17, 2020**
- Major refactoring and rewrite of the library
- Units are now independent from dimensions
- Dimensions now depend on units (base or coherent units are provided in a class template)
- Quantity gets a Dimension template parameter again (as unit does not provide information about
its dimension anymore)
- Spaceship operator support added
- Added official CGS system support
- Added official data information system support
- Repository file tree cleanup
- `ratio` refactored to contain `Exp` template parameter (thanks a lot [@oschonrock](https://github.com/oschonrock)!)
- SI fundamental constants added
- `q_` prefix applied to all the UDLs (thanks [@kwikius](https://github.com/kwikius))
- `unknown_unit` renamed to `unknown_coherent_unit`
- Project documentation greatly extended and switched to Sphinx
- A few more usage examples added
- ASCII-only output support added (thanks [@yasamoka](https://github.com/yasamoka))
- Representation values formatting extended (thanks [@rbrugo](https://github.com/rbrugo))
- Output streams formatting support added
- Linear algebra from `std::experimental::math` support added
- Named SI units and their dimensions added (thanks [@rbrugo](https://github.com/rbrugo)
- libfmt updated to 6.2.0
- Added absolute functions and epsilon to math.h (thanks [@mikeford3](https://github.com/mikeford3))
- Added a lot of prefixes to named units and introduced `alias_unit` (thanks [@yasamoka](https://github.com/yasamoka))
- Linking with Conan targets only when they exists ([#98](https://github.com/mpusz/units/issues/98))
- All physical dimensions and units put into `physical` namespace
- CMake improvements
- Velocity renamed to speed
Many thanks to GitHub users [@oschonrock](https://github.com/oschonrock),
[@kwikius](https://github.com/kwikius), and [@i-ky](https://github.com/i-ky) for their support
in drafting a new library design.
- **0.4.0 Nov 17, 2019**
- Support for derived dimensions in `exp` added
- Added `pow()` and `sqrt()` operations on quantities
- `units` removed from a `std::experimental` namespace
- Downcasting facility refactored so the user does not have to write the boilerplate code anymore
- From now on base dimensions should inherit from `base_dimension` class template
- Added unit symbols definitions to `base_dimension` and derived units
- Added support for `operator<<` on `quantity`
- `fmt` support added
- Derived unit factory helpers refactored
- Refactored the way prefixed units are defined
- **0.3.1 Sep 18, 2019**
- cmcstl2 dependency changed to range-v3 0.9.1
- **0.3.0 Sep 16, 2019 (CppCon 2019 design)**
- The design as described on CppCon 2019 talk (<https://youtu.be/0YW6yxkdhlU>)
- Applied the feedback from the Cologne evening session
- `upcasting_traits` renamed to `downcasting_traits`
- `Dimension` template parameter removed from quantity
- `units` moved to a `std::experimental` namespace
- Leading underscore prefix removed from UDLs
- Added a few more derived dimensions
- `meter` renamed to `metre`
- Missing `operator*` added
- Predefined dimensions moved to a dedicated directory
- `dimension_` prefix removed from names of derived dimensions
- cmcstl2 library updated to 2019.09.19
- `base_dimension` is a value provided as `const&` to the `exp` type
- integrated with Compiler Explorer
- gsl-lite dependency removed
- Fractional dimension exponents support added
- `QuantityOf` concept introduced
- `quantity_cast<U, Rep>()` support added
- **0.2.0 July 18, 2019 (C++Now 2019 design)**
- The design as described on C++Now 2019 talk (<https://youtu.be/wKchCktZPHU>)
- Added C++20 features supported by gcc-9.1 (`std::remove_cvref_t`, down with typename, `std::type_identity`)
- Compile-time performance optimizations (`type_list`, `common_ratio`, `ratio`, `conditional_t`)
- **0.1.0 May 18, 2019**
- Initial library release
- Begin semantic versioning
- The last version to work with gcc-8

View File

@ -1,261 +0,0 @@
# The MIT License (MIT)
#
# Copyright (c) 2018 Mateusz Pusz
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
cmake_minimum_required(VERSION 3.2)
option(${projectPrefix}BUILD_DOCS "Generate project documentation" ON)
message(STATUS "${projectPrefix}BUILD_DOCS: ${${projectPrefix}BUILD_DOCS}")
if(NOT ${projectPrefix}BUILD_DOCS)
return()
endif()
# set paths to Conan packages (needed for doxygen)
# TODO: remove when Conan will learn how to properly create imported build tools targets
include(${CMAKE_BINARY_DIR}/conan_paths.cmake OPTIONAL)
# Find all the public headers
file(GLOB_RECURSE unitsPublicHeaders "${PROJECT_SOURCE_DIR}/src/*.h")
# Sphinx documentation dependencies
set(unitsSphinxDocs
"${CMAKE_CURRENT_SOURCE_DIR}/_static/css/custom.css"
"${CMAKE_CURRENT_SOURCE_DIR}/_static/img/concepts.svg"
"${CMAKE_CURRENT_SOURCE_DIR}/_static/img/dimensions.svg"
"${CMAKE_CURRENT_SOURCE_DIR}/_static/img/downcast_1.png"
"${CMAKE_CURRENT_SOURCE_DIR}/_static/img/downcast_2.png"
"${CMAKE_CURRENT_SOURCE_DIR}/_static/img/units.svg"
"${CMAKE_CURRENT_SOURCE_DIR}/_static/img/quantity_like.svg"
"${CMAKE_CURRENT_SOURCE_DIR}/CHANGELOG.md"
"${CMAKE_CURRENT_SOURCE_DIR}/defining_systems.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/defining_systems/angular_units.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/defining_systems/isq.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/defining_systems/si.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/design.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/design/directories.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/design/downcasting.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/design/quantity.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/design/quantity_kind.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/basics.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/basics/avg_speed.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/basics/box_example.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/basics/capacitor_time_curve.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/basics/clcpp_response.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/basics/experimental_angle.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/basics/foot_pound_second.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/basics/glide_computer.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/basics/hello_units.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/basics/total_energy.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/basics/unknown_dimension.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/custom_representation.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/custom_representation/linear_algebra.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/custom_representation/measurement.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/custom_systems.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/custom_systems/custom_systems.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/custom_utilities.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/custom_utilities/conversion_factor.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/kalman_filter.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/kalman_filter/example_1.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/kalman_filter/example_2.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/kalman_filter/example_3.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/kalman_filter/example_4.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/kalman_filter/example_5.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/kalman_filter/example_6.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/kalman_filter/example_7.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/kalman_filter/example_8.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/kalman_filter/kalman.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/faq.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/framework.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/framework/arithmetics.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/framework/basic_concepts.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/framework/constants.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/framework/conversions_and_casting.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/framework/dimensions.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/framework/magnitudes.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/framework/quantities.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/framework/quantity_kinds.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/framework/quantity_like.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/framework/quantity_points.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/framework/text_output.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/framework/units.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/genindex.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/glossary.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/index.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/introduction.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/quick_start.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/core.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/core/concepts.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/core/customization_points.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/core/downcasting.rst"
# "${CMAKE_CURRENT_SOURCE_DIR}/reference/core/functions.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/core/metafunctions.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/core/types.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/core/types/dimensions.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/core/types/kinds.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/core/types/prefixes.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/core/types/reference.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/core/types/quantity.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/core/types/quantity_kind.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/core/types/quantity_point_kind.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/core/types/quantity_point.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/core/types/units.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/core/types/utilities.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/core/types/utilities/basic_fixed_string.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/core/types/utilities/basic_symbol_text.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/core/types/utilities/ratio.rst"
# "${CMAKE_CURRENT_SOURCE_DIR}/reference/math.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/random.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/generic.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/generic/angle.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/generic/dimensionless.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/generic/unknown.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/iec80000.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/iec80000/binary_prefixes.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/iec80000/modulation_rate.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/iec80000/storage_capacity.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/iec80000/traffic_intensity.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/iec80000/transfer_rate.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/natural.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/natural/acceleration.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/natural/constants.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/natural/energy.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/natural/force.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/natural/length.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/natural/mass.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/natural/momentum.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/natural/speed.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/natural/time.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/natural/units.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si_cgs.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/cgs/length.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/cgs/acceleration.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/cgs/area.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/cgs/energy.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/cgs/force.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/cgs/length.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/cgs/mass.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/cgs/power.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/cgs/pressure.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/cgs/speed.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/cgs/time.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/dimensions_and_concepts.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si_fps.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/fps/length.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/fps/acceleration.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/fps/area.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/fps/density.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/fps/energy.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/fps/force.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/fps/length.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/fps/mass.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/fps/power.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/fps/pressure.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/fps/speed.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/fps/time.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/fps/volume.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si_iau.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/iau/length.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si_imperial.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/imperial/length.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si_international.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/international/area.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/international/length.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/international/speed.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/international/volume.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/absorbed_dose.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/acceleration.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/amount_of_substance.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/area.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/capacitance.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/catalytic_activity.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/charge_density.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/concentration.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/conductance.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/constants.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/current_density.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/density.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/dynamic_viscosity.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/electric_charge.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/electric_current.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/electric_field_strength.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/energy.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/force.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/frequency.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/heat_capacity.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/inductance.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/length.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/luminance.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/luminous_intensity.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/magnetic_flux.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/magnetic_induction.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/mass.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/molar_energy.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/momentum.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/permeability.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/permittivity.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/power.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/prefixes.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/pressure.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/resistance.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/speed.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/surface_tension.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/thermal_conductivity.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/thermodynamic_temperature.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/time.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/voltage.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/volume.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si_typographic.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/typographic/length.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si_uscs.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems/isq/si/uscs/length.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/references.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/use_cases.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/use_cases/custom_representation_types.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/use_cases/extensions.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/use_cases/interoperability.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/use_cases/legacy_interfaces.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/use_cases/linear_algebra.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/use_cases/natural_units.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/use_cases/unknown_dimensions.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/usage.rst"
)
include(documentation)
include(GNUInstallDirs)
add_documentation(
documentation ALL
BREATHE_PROJECT mp-units
CODE_SOURCE_DIR "${PROJECT_SOURCE_DIR}/src"
INSTALL_DIR ${CMAKE_INSTALL_DOCDIR}
CODE_DEPENDS ${unitsPublicHeaders}
DOCS_DEPENDS ${unitsSphinxDocs}
)
add_custom_command(
TARGET documentation POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/_static/img/*.svg
${CMAKE_CURRENT_BINARY_DIR}/sphinx/_images
)

View File

@ -1,93 +0,0 @@
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
# into which the generated documentation will be written. If a relative path is
# entered, it will be relative to the location where doxygen was started. If
# left blank the current directory will be used.
OUTPUT_DIRECTORY = "@DOXYGEN_OUTPUT_DIR@"
# The INPUT tag is used to specify the files and/or directories that contain
# documented source files. You may enter file names like myfile.cpp or
# directories like /usr/src/myproject. Separate the files or directories with
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
INPUT = "@DOXYGEN_INPUT_DIR@"
# The RECURSIVE tag can be used to specify whether or not subdirectories should
# be searched for input files as well.
# The default value is: NO.
RECURSIVE = YES
# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
# to include (a tag file for) the STL sources as input, then you should set this
# tag to YES in order to let doxygen match functions declarations and
# definitions whose arguments contain STL classes (e.g. func(std::string);
# versus func(std::string) {}). This also make the inheritance and collaboration
# diagrams that involve STL classes more complete and accurate.
# The default value is: NO.
BUILTIN_STL_SUPPORT = YES
# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
# The default value is: YES.
GENERATE_HTML = NO
# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
# The default value is: YES.
GENERATE_LATEX = NO
# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
# captures the structure of the code including all documentation.
# The default value is: NO.
GENERATE_XML = YES
# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
# documentation are documented, even if no documentation was available. Private
# class members and static file members will be hidden unless the
# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
# Note: This will also disable the warnings about undocumented members that are
# normally produced when WARNINGS is set to YES.
# The default value is: NO.
EXTRACT_ALL = YES
# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
# included in the documentation.
# The default value is: NO.
EXTRACT_STATIC = YES
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
# (namespaces, classes, functions, etc.) that should be excluded from the
# output. The symbol name can be a fully qualified name, a word, or if the
# wildcard * is used, a substring. Examples: ANamespace, AClass,
# AClass::ANamespace, ANamespace::*Test
#
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories use the pattern */test/*
EXCLUDE_SYMBOLS = units::detail
# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
# will automatically be disabled.
# The default value is: YES.
WARN_IF_UNDOCUMENTED = YES
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
# a warning is encountered.
# The default value is: NO.
WARN_AS_ERROR = NO
# The QUIET tag can be used to turn on/off the messages that are generated to
# standard output by doxygen. If QUIET is set to YES this implies that the
# messages are off.
# The default value is: NO.
QUIET = YES

View File

@ -1,20 +0,0 @@
@import 'theme.css';
a.reference.internal + code.sig-name.descname {
padding-left: 4px;
}
.breatheparameterlist li tt + p {
display: inline;
}
.breatheenumvalues li tt + p {
display: inline;
}
.rst-content .admonition-try-it-on-compiler-explorer {
background-color: #e2f6d5;
}
.rst-content .admonition-try-it-on-compiler-explorer > .admonition-title {
background-color: #66c52a;
}

View File

@ -1,116 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="818px" preserveAspectRatio="none" style="width:925px;height:818px;background:#FCFCFC;" version="1.1" viewBox="0 0 925 818" width="925px" zoomAndPan="magnify"><defs/><g><!--MD5=[df5443ea73757c949ae3b56ebe1f85be]
cluster Kind--><a href="../../framework/quantity_kinds.html#kind-creation" target="_top" title="../../framework/quantity_kinds.html#kind-creation" xlink:actuate="onRequest" xlink:href="../../framework/quantity_kinds.html#kind-creation" xlink:show="new" xlink:title="../../framework/quantity_kinds.html#kind-creation" xlink:type="simple"><rect fill="#FCFCFC" height="91" style="stroke:#000000;stroke-width:1.5;" width="167" x="193" y="244"/><path d="M238,244 L238,253.2969 L228,263.2969 L193,263.2969 " fill="none" style="stroke:#000000;stroke-width:1.5;"/><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacing" textLength="35" x="196" y="257.9951">Kind</text></a><!--MD5=[7347e2c91daf6e188383fd600ba11b33]
cluster PointKind--><a href="../../framework/quantity_kinds.html#quantity-point-kinds" target="_top" title="../../framework/quantity_kinds.html#quantity-point-kinds" xlink:actuate="onRequest" xlink:href="../../framework/quantity_kinds.html#quantity-point-kinds" xlink:show="new" xlink:title="../../framework/quantity_kinds.html#quantity-point-kinds" xlink:type="simple"><rect fill="#FCFCFC" height="91" style="stroke:#000000;stroke-width:1.5;" width="241" x="60" y="537.5"/><path d="M148,537.5 L148,546.7969 L138,556.7969 L60,556.7969 " fill="none" style="stroke:#000000;stroke-width:1.5;"/><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacing" textLength="78" x="63" y="551.4951">PointKind</text></a><!--MD5=[902b17ab3dc1ff87bf436c5d5e991ce7]
cluster PointOrigin--><a href="../../framework/quantity_points.html#point-origins" target="_top" title="../../framework/quantity_points.html#point-origins" xlink:actuate="onRequest" xlink:href="../../framework/quantity_points.html#point-origins" xlink:show="new" xlink:title="../../framework/quantity_points.html#point-origins" xlink:type="simple"><rect fill="#FCFCFC" height="91" style="stroke:#000000;stroke-width:1.5;" width="211" x="400" y="244"/><path d="M502,244 L502,253.2969 L492,263.2969 L400,263.2969 " fill="none" style="stroke:#000000;stroke-width:1.5;"/><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacing" textLength="92" x="403" y="257.9951">PointOrigin</text></a><!--MD5=[ce5ab648b60979218cea37a66686aafa]
cluster Quantity--><a href="../../framework/quantities.html" target="_top" title="../../framework/quantities.html" xlink:actuate="onRequest" xlink:href="../../framework/quantities.html" xlink:show="new" xlink:title="../../framework/quantities.html" xlink:type="simple"><rect fill="#FCFCFC" height="112" style="stroke:#000000;stroke-width:1.5;" width="251" x="531" y="375"/><path d="M613,375 L613,384.2969 L603,394.2969 L531,394.2969 " fill="none" style="stroke:#000000;stroke-width:1.5;"/><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacing" textLength="72" x="534" y="388.9951">Quantity</text></a><!--MD5=[322ec44ab3fdb4211708329edccee368]
cluster QuantityPoint--><a href="../../framework/quantity_points.html" target="_top" title="../../framework/quantity_points.html" xlink:actuate="onRequest" xlink:href="../../framework/quantity_points.html" xlink:show="new" xlink:title="../../framework/quantity_points.html" xlink:type="simple"><rect fill="#FCFCFC" height="112" style="stroke:#000000;stroke-width:1.5;" width="291" x="628" y="527"/><path d="M753,527 L753,536.2969 L743,546.2969 L628,546.2969 " fill="none" style="stroke:#000000;stroke-width:1.5;"/><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacing" textLength="115" x="631" y="540.9951">QuantityPoint</text></a><!--MD5=[64a7dbcb99a03de11a63a2b4b9c040ec]
cluster QuantityKind--><a href="../../framework/quantity_kinds.html" target="_top" title="../../framework/quantity_kinds.html" xlink:actuate="onRequest" xlink:href="../../framework/quantity_kinds.html" xlink:show="new" xlink:title="../../framework/quantity_kinds.html" xlink:type="simple"><rect fill="#FCFCFC" height="112" style="stroke:#000000;stroke-width:1.5;" width="247" x="341" y="527"/><path d="M458,527 L458,536.2969 L448,546.2969 L341,546.2969 " fill="none" style="stroke:#000000;stroke-width:1.5;"/><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacing" textLength="107" x="344" y="540.9951">QuantityKind</text></a><!--MD5=[8bab1fe1e45831c182205808cde691dc]
cluster QuantityPointKind--><a href="../../framework/quantity_kinds.html#quantity-point-kinds" target="_top" title="../../framework/quantity_kinds.html#quantity-point-kinds" xlink:actuate="onRequest" xlink:href="../../framework/quantity_kinds.html#quantity-point-kinds" xlink:show="new" xlink:title="../../framework/quantity_kinds.html#quantity-point-kinds" xlink:type="simple"><rect fill="#FCFCFC" height="112" style="stroke:#000000;stroke-width:1.5;" width="313" x="69" y="700"/><path d="M229,700 L229,709.2969 L219,719.2969 L69,719.2969 " fill="none" style="stroke:#000000;stroke-width:1.5;"/><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacing" textLength="150" x="72" y="713.9951">QuantityPointKind</text></a><!--MD5=[393655ea98b8cc7762ecac08ac25a8bc]
entity Unit--><a href="../../framework/units.html" target="_top" title="../../framework/units.html" xlink:actuate="onRequest" xlink:href="../../framework/units.html" xlink:show="new" xlink:title="../../framework/units.html" xlink:type="simple"><rect fill="#FCFCFC" height="46.2969" style="stroke:#000000;stroke-width:1.5;" width="69" x="373.5" y="7"/><path d="M396.5,7 L396.5,12 L389.5,19 L373.5,19 " fill="none" style="stroke:#000000;stroke-width:1.5;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="29" x="388.5" y="39.9951">Unit</text></a><!--MD5=[203769626a5b736eb6e04c0d5326ab96]
entity Dimension--><a href="../../framework/dimensions.html" target="_top" title="../../framework/dimensions.html" xlink:actuate="onRequest" xlink:href="../../framework/dimensions.html" xlink:show="new" xlink:title="../../framework/dimensions.html" xlink:type="simple"><rect fill="#FCFCFC" height="46.2969" style="stroke:#000000;stroke-width:1.5;" width="116" x="350" y="113"/><path d="M388.6667,113 L388.6667,118 L381.6667,125 L350,125 " fill="none" style="stroke:#000000;stroke-width:1.5;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="76" x="365" y="145.9951">Dimension</text></a><!--MD5=[ea03bdbd065578ac5244a06dd30cb289]
class kind--><a href="../../framework/quantity_kinds.html#kind-creation" target="_top" title="../../framework/quantity_kinds.html#kind-creation" xlink:actuate="onRequest" xlink:href="../../framework/quantity_kinds.html#kind-creation" xlink:show="new" xlink:title="../../framework/quantity_kinds.html#kind-creation" xlink:type="simple"><rect codeLine="16" fill="#F8F8F8" height="23.9688" id="kind" style="stroke:#383838;stroke-width:1.5;" width="99" x="236.5" y="287"/><text fill="#000000" font-family="sans-serif" font-size="12" font-style="italic" lengthAdjust="spacing" textLength="26" x="239.5" y="303.1387">kind</text><rect fill="#FCFCFC" height="15.9688" style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" width="65" x="273.5" y="284"/><text fill="#000000" font-family="sans-serif" font-size="12" font-style="italic" lengthAdjust="spacing" textLength="63" x="274.5" y="296.1387">Dimension</text></a><!--MD5=[687e1f7389fc36adbc8b00efbcc9e77a]
class point_kind--><a href="../../framework/quantity_kinds.html#quantity-point-kinds" target="_top" title="../../framework/quantity_kinds.html#quantity-point-kinds" xlink:actuate="onRequest" xlink:href="../../framework/quantity_kinds.html#quantity-point-kinds" xlink:show="new" xlink:title="../../framework/quantity_kinds.html#quantity-point-kinds" xlink:type="simple"><rect codeLine="20" fill="#F8F8F8" height="23.9688" id="point_kind" style="stroke:#383838;stroke-width:1.5;" width="174" x="103" y="580.5"/><text fill="#000000" font-family="sans-serif" font-size="12" font-style="italic" lengthAdjust="spacing" textLength="63" x="106" y="596.6387">point_kind</text><rect fill="#FCFCFC" height="15.9688" style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" width="103" x="177" y="577.5"/><text fill="#000000" font-family="sans-serif" font-size="12" font-style="italic" lengthAdjust="spacing" textLength="101" x="178" y="589.6387">Kind, PointOrigin</text></a><!--MD5=[9db4689932f79289c10697e18a3c06c1]
class point_origin--><a href="../../framework/quantity_points.html#point-origins" target="_top" title="../../framework/quantity_points.html#point-origins" xlink:actuate="onRequest" xlink:href="../../framework/quantity_points.html#point-origins" xlink:show="new" xlink:title="../../framework/quantity_points.html#point-origins" xlink:type="simple"><rect codeLine="24" fill="#F8F8F8" height="23.9688" id="point_origin" style="stroke:#383838;stroke-width:1.5;" width="144" x="443" y="287"/><text fill="#000000" font-family="sans-serif" font-size="12" font-style="italic" lengthAdjust="spacing" textLength="71" x="446" y="303.1387">point_origin</text><rect fill="#FCFCFC" height="15.9688" style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" width="65" x="525" y="284"/><text fill="#000000" font-family="sans-serif" font-size="12" font-style="italic" lengthAdjust="spacing" textLength="63" x="526" y="296.1387">Dimension</text></a><!--MD5=[da1b011f603b1fa92adce02fc4bac354]
class quantity--><a href="../../framework/quantities.html#construction" target="_top" title="../../framework/quantities.html#construction" xlink:actuate="onRequest" xlink:href="../../framework/quantities.html#construction" xlink:show="new" xlink:title="../../framework/quantities.html#construction" xlink:type="simple"><rect codeLine="28" fill="#F8F8F8" height="44.7734" id="quantity" style="stroke:#383838;stroke-width:1.5;" width="184" x="574" y="418"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="47" x="577" y="434.1387">quantity</text><rect fill="#FCFCFC" height="15.9688" style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" width="129" x="632" y="415"/><text fill="#000000" font-family="sans-serif" font-size="12" font-style="italic" lengthAdjust="spacing" textLength="127" x="633" y="427.1387">Dimension, Unit, Rep</text><line style="stroke:#383838;stroke-width:1.5;" x1="575" x2="757" y1="441.9688" y2="441.9688"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="75" x="580" y="456.1792">rep number()</text></a><!--MD5=[18fbdc711d33f9ff282e1f4c30c050e6]
class quantity_point--><a href="../../framework/quantity_points.html#construction" target="_top" title="../../framework/quantity_points.html#construction" xlink:actuate="onRequest" xlink:href="../../framework/quantity_points.html#construction" xlink:show="new" xlink:title="../../framework/quantity_points.html#construction" xlink:type="simple"><rect codeLine="34" fill="#F8F8F8" height="44.7734" id="quantity_point" style="stroke:#383838;stroke-width:1.5;" width="223" x="671.5" y="570"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="83" x="674.5" y="586.1387">quantity_point</text><rect fill="#FCFCFC" height="15.9688" style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" width="132" x="765.5" y="567"/><text fill="#000000" font-family="sans-serif" font-size="12" font-style="italic" lengthAdjust="spacing" textLength="130" x="766.5" y="579.1387">PointOrigin, Unit, Rep</text><line style="stroke:#383838;stroke-width:1.5;" x1="672.5" x2="893.5" y1="593.9688" y2="593.9688"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="102" x="677.5" y="608.1792">quantity relative()</text></a><!--MD5=[5b6ab379e9f247363b208f7c72246136]
class quantity_kind--><a href="../../framework/quantity_kinds.html#construction" target="_top" title="../../framework/quantity_kinds.html#construction" xlink:actuate="onRequest" xlink:href="../../framework/quantity_kinds.html#construction" xlink:show="new" xlink:title="../../framework/quantity_kinds.html#construction" xlink:type="simple"><rect codeLine="40" fill="#F8F8F8" height="44.7734" id="quantity_kind" style="stroke:#383838;stroke-width:1.5;" width="179" x="384.5" y="570"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="78" x="387.5" y="586.1387">quantity_kind</text><rect fill="#FCFCFC" height="15.9688" style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" width="93" x="473.5" y="567"/><text fill="#000000" font-family="sans-serif" font-size="12" font-style="italic" lengthAdjust="spacing" textLength="91" x="474.5" y="579.1387">Kind, Unit, Rep</text><line style="stroke:#383838;stroke-width:1.5;" x1="385.5" x2="562.5" y1="593.9688" y2="593.9688"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="107" x="390.5" y="608.1792">quantity common()</text></a><!--MD5=[6d322596e71f19471be4dbdd0c5e34a1]
class quantity_point_kind--><a href="../../framework/quantity_kinds.html#quantity-point-kinds" target="_top" title="../../framework/quantity_kinds.html#quantity-point-kinds" xlink:actuate="onRequest" xlink:href="../../framework/quantity_kinds.html#quantity-point-kinds" xlink:show="new" xlink:title="../../framework/quantity_kinds.html#quantity-point-kinds" xlink:type="simple"><rect codeLine="46" fill="#F8F8F8" height="44.7734" id="quantity_point_kind" style="stroke:#383838;stroke-width:1.5;" width="245" x="112.5" y="743"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="114" x="115.5" y="759.1387">quantity_point_kind</text><rect fill="#FCFCFC" height="15.9688" style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" width="123" x="237.5" y="740"/><text fill="#000000" font-family="sans-serif" font-size="12" font-style="italic" lengthAdjust="spacing" textLength="121" x="238.5" y="752.1387">PointKind, Unit, Rep</text><line style="stroke:#383838;stroke-width:1.5;" x1="113.5" x2="356.5" y1="766.9688" y2="766.9688"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="131" x="118.5" y="781.1792">quantity_kind relative()</text></a><!--MD5=[cc29d0a880a167f6baed24f1904eef31]
reverse link Unit to Dimension--><path d="M408,58.192 C408,75.262 408,96.989 408,112.976 " fill="none" id="Unit-backto-Dimension" style="stroke:#383838;stroke-width:1.0;stroke-dasharray:7.0,7.0;"/><polygon fill="#383838" points="408,53.056,404,62.056,408,58.056,412,62.056,408,53.056" style="stroke:#383838;stroke-width:1.0;"/><!--MD5=[0b98293d9a517e9db9c4d9c6d74de02a]
reverse link Dimension to Quantity--><path d="M470.945,148.015 C516.207,159.579 574.149,182.699 603,228 C632.366,274.11 638.11,309.098 603,351 C589.954,366.57 572.759,345.043 558,359 C554.7656,362.0586 552.036,365.5569 549.7362,369.3436 C549.1613,370.2902 548.6132,371.2549 548.0909,372.2352 C547.8297,372.7254 547.5749,373.2195 547.3264,373.7172 C547.2022,373.966 547.0795,374.2158 546.9584,374.4664 C546.8978,374.5917 546.8377,374.7173 546.7779,374.843 " fill="none" id="Dimension-backto-Quantity" style="stroke:#383838;stroke-width:1.0;stroke-dasharray:7.0,7.0;"/><polygon fill="#383838" points="466.05,146.796,473.8179,152.8508,470.9021,148.0033,475.7495,145.0875,466.05,146.796" style="stroke:#383838;stroke-width:1.0;"/><!--MD5=[fc31f3d5d7e3482da677a28e231832f1]
reverse link Unit to Quantity--><path d="M447.467,50.131 C502.971,79.525 601.795,141.597 642,228 C665.063,277.564 678.777,310.554 642,351 C629.385,364.873 572.134,346.678 558,359 C554.6445,361.9251 551.823,365.3223 549.4555,369.0342 C548.2717,370.8901 547.2014,372.8248 546.2346,374.8185 " fill="none" id="Unit-backto-Quantity" style="stroke:#383838;stroke-width:1.0;stroke-dasharray:7.0,7.0;"/><polygon fill="#383838" points="442.891,47.729,449.0002,55.4541,447.318,50.0532,452.7189,48.371,442.891,47.729" style="stroke:#383838;stroke-width:1.0;"/><!--MD5=[af7c6403d4c00eaf6863e827abf137ba]
reverse link Dimension to Kind--><path d="M344.831,152.802 C303.642,166.251 251.814,189.65 220,228 C217.5076,231.0044 215.3403,234.3076 213.4558,237.7932 C212.5135,239.536 211.642,241.3245 210.8359,243.1439 C210.7351,243.3714 210.6353,243.5993 210.5366,243.8277 " fill="none" id="Dimension-backto-Kind" style="stroke:#383838;stroke-width:1.0;stroke-dasharray:7.0,7.0;"/><polygon fill="#383838" points="349.8,151.211,340.0087,150.1481,345.0385,152.7367,342.4499,157.7666,349.8,151.211" style="stroke:#383838;stroke-width:1.0;"/><!--MD5=[e0820a2743574ce16047da1026a45d42]
reverse link Dimension to PointOrigin--><path d="M408,164.077 C408,175.3583 408,189.1913 408,203.6384 C408,210.862 408,218.2391 408,225.5276 C408,229.1718 408,232.7939 408,236.3636 C408,238.1484 408,239.9201 408,241.6749 C408,242.1136 408,242.5512 408,242.9878 C408,243.206 408,243.424 408,243.6417 " fill="none" id="Dimension-backto-PointOrigin" style="stroke:#383838;stroke-width:1.0;stroke-dasharray:7.0,7.0;"/><polygon fill="#383838" points="408,159.049,404,168.049,408,164.049,412,168.049,408,159.049" style="stroke:#383838;stroke-width:1.0;"/><!--MD5=[0171a2a578dda2fb989d4518d60e2add]
reverse link PointOrigin to PointKind--><path d="M399.9204,307.7672 C399.6824,307.9939 399.4399,308.2246 399.1932,308.4592 C398.2064,309.3976 397.1513,310.3983 396.0354,311.4529 C393.8037,313.562 391.3291,315.887 388.673,318.3616 C378.0485,328.26 364.5185,340.552 352,351 C266.556,422.313 256.085,461.053 153,503 C139.316,508.568 98.011,501.15 87,511 C80.3646,516.936 75.8288,524.7184 72.7648,533.1048 C72.3818,534.1531 72.0218,535.2108 71.6836,536.2755 C71.599,536.5417 71.5158,536.8083 71.4339,537.0754 C71.393,537.2089 71.3524,537.3425 71.3122,537.4762 " fill="none" id="PointOrigin-backto-PointKind" style="stroke:#383838;stroke-width:1.0;stroke-dasharray:7.0,7.0;"/><polygon fill="#383838" points="399.9204,307.7672,390.6445,311.0773,396.2996,311.2154,396.1615,316.8706,399.9204,307.7672" style="stroke:#383838;stroke-width:1.0;"/><!--MD5=[d2ac93a9f2f8e7f09e3b64c12255ee7d]
reverse link Kind to PointKind--><path d="M192.7677,312.4035 C191.175,314.8435 189.3808,317.6118 187.4119,320.6797 C179.5361,332.9512 168.8633,350.0162 157.0968,370.0396 C133.5638,410.0865 105.656,461.967 87,511 C83.834,519.321 81.0871,528.3333 78.7419,537.2139 " fill="none" id="Kind-backto-PointKind" style="stroke:#383838;stroke-width:1.0;stroke-dasharray:7.0,7.0;"/><polygon fill="#383838" points="192.7677,312.4035,184.4987,317.7536,190.0346,316.5905,191.1978,322.1265,192.7677,312.4035" style="stroke:#383838;stroke-width:1.0;"/><!--MD5=[fd164a02e043296bed0ac24e8dea3999]
reverse link Unit to QuantityPoint--><path d="M447.88,30.995 C551.995,33.277 824,54.938 824,219 C824,219 824,219 824,300 C824,392.919 845.175,443.267 774,503 C753.698,520.038 675.219,493.863 655,511 C651.6041,513.8781 648.7521,517.2396 646.3619,520.9252 C645.1669,522.768 644.0873,524.6919 643.1129,526.6768 " fill="none" id="Unit-backto-QuantityPoint" style="stroke:#383838;stroke-width:1.0;stroke-dasharray:7.0,7.0;"/><polygon fill="#383838" points="442.752,30.895,451.6726,35.0691,447.7511,30.9922,451.828,27.0706,442.752,30.895" style="stroke:#383838;stroke-width:1.0;"/><!--MD5=[70cd19cb2aca3701b75cff1362c25352]
reverse link PointOrigin to QuantityPoint--><path d="M417.0792,335.5885 C417.1578,335.8517 417.2369,336.1159 417.3166,336.3812 C417.4759,336.9117 417.6375,337.4465 417.8014,337.9854 C419.1121,342.297 420.5668,346.8737 422.1727,351.6604 C425.3844,361.2337 429.2009,371.6468 433.6805,382.4578 C451.599,425.7015 480.1275,475.3105 523,503 C544.489,516.879 558.207,497.602 580,511 C597.984,522.056 611.6847,541.2883 621.0323,558.1821 C623.3691,562.4056 625.4339,566.4829 627.2255,570.2498 C627.4495,570.7207 627.6692,571.1867 627.8846,571.6475 " fill="none" id="PointOrigin-backto-QuantityPoint" style="stroke:#383838;stroke-width:1.0;stroke-dasharray:7.0,7.0;"/><polygon fill="#383838" points="417.0792,335.5885,415.8213,345.3567,418.5097,340.3795,423.4869,343.068,417.0792,335.5885" style="stroke:#383838;stroke-width:1.0;"/><!--MD5=[4824db4e5b398e43184a581563085055]
link quantity to quantity_point--><path codeLine="64" d="M683.013,463.311 C702.682,488.529 735.244,530.274 757.841,559.246 " fill="none" id="quantity-to-quantity_point" style="stroke:#383838;stroke-width:1.0;"/><polygon fill="#383838" points="765.967,569.662,765.4305,562.4709,758.5862,560.2003,759.1227,567.3914,765.967,569.662" style="stroke:#383838;stroke-width:1.0;"/><!--MD5=[d771781a58c6bc6a1155ff477a9676a1]
reverse link Unit to QuantityKind--><path d="M368.366,40.059 C295.58,59.302 148,111.565 148,219 C148,219 148,219 148,300 C148,395.581 144.142,443.569 219,503 C244.908,523.569 264.548,494.124 293,511 C311.157,521.7695 324.863,540.993 334.17,557.9539 C336.4968,562.1941 338.5486,566.2929 340.3263,570.0828 C340.5485,570.5566 340.7664,571.0255 340.98,571.4893 " fill="none" id="Unit-backto-QuantityKind" style="stroke:#383838;stroke-width:1.0;stroke-dasharray:7.0,7.0;"/><polygon fill="#383838" points="373.474,38.73,363.7564,37.1271,368.6354,39.99,365.7725,44.8689,373.474,38.73" style="stroke:#383838;stroke-width:1.0;"/><!--MD5=[df745d6e016be8f34c5f8c120fb76388]
reverse link Kind to QuantityKind--><path d="M213.3487,335.0716 C213.3831,335.1598 213.4176,335.2481 213.4521,335.3364 C213.5902,335.6896 213.729,336.0431 213.8683,336.3967 C214.147,337.1039 214.4282,337.8118 214.7115,338.5193 C215.2781,339.9344 215.8535,341.3479 216.436,342.7521 C217.6008,345.5603 218.7936,348.3309 220,351 C244.587,405.4015 276.2213,464.5123 302.0095,510.5179 C314.9036,533.5207 326.3363,553.2472 334.6957,567.4707 C336.7856,571.0265 338.6834,574.2385 340.3639,577.0716 C340.574,577.4258 340.7807,577.774 340.9839,578.1163 " fill="none" id="Kind-backto-QuantityKind" style="stroke:#383838;stroke-width:1.0;stroke-dasharray:7.0,7.0;"/><polygon fill="#383838" points="213.3487,335.0716,212.8947,344.91,215.1666,339.7294,220.3472,342.0013,213.3487,335.0716" style="stroke:#383838;stroke-width:1.0;"/><!--MD5=[c1804ecabd485ae0f6f9feb5d83c0cf7]
link quantity to quantity_kind--><path codeLine="68" d="M638.082,463.311 C604.855,489.269 549.212,532.74 512.062,561.764 " fill="none" id="quantity-to-quantity_kind" style="stroke:#383838;stroke-width:1.0;"/><polygon fill="#383838" points="501.641,569.906,508.8317,569.3644,511.0975,562.5186,503.9068,563.0601,501.641,569.906" style="stroke:#383838;stroke-width:1.0;"/><!--MD5=[41588c27c6e4d927cf9148a254d0b3d7]
reverse link Unit to QuantityPointKind--><path d="M368.078,31.546 C266.463,35.252 6,60.236 6,219 C6,219 6,219 6,593.5 C6,634.0025 23.1997,676.0599 40.668,708.3298 C49.4022,724.4648 58.2036,738.153 64.9558,747.9765 C65.7998,749.2044 66.6118,750.372 67.3877,751.4764 C67.7756,752.0286 68.1545,752.565 68.5238,753.0853 C68.6162,753.2153 68.7079,753.3444 68.799,753.4724 " fill="none" id="Unit-backto-QuantityPointKind" style="stroke:#383838;stroke-width:1.0;stroke-dasharray:7.0,7.0;"/><polygon fill="#383838" points="373.378,31.367,364.2472,27.6753,368.3809,31.537,364.5192,35.6707,373.378,31.367" style="stroke:#383838;stroke-width:1.0;"/><!--MD5=[7bf21d8cbe84c4088afc37d2e279dcea]
reverse link PointKind to QuantityPointKind--><path d="M69.8533,628.7128 C69.8674,628.9804 69.8815,629.249 69.8957,629.5186 C69.9241,630.0579 69.9527,630.6011 69.9815,631.1482 C70.0391,632.2423 70.0975,633.3519 70.1566,634.4757 C70.3932,638.971 70.6418,643.694 70.8983,648.5688 C71.4115,658.3184 71.9566,668.6752 72.5016,679.0313 C72.7742,684.2093 73.0467,689.3872 73.3152,694.489 C73.3823,695.7645 73.4492,697.0352 73.5158,698.2999 C73.5324,698.6161 73.549,698.9319 73.5656,699.2473 C73.5739,699.4051 73.5822,699.5627 73.5905,699.7202 " fill="none" id="PointKind-backto-QuantityPointKind" style="stroke:#383838;stroke-width:1.0;stroke-dasharray:7.0,7.0;"/><polygon fill="#383838" points="69.8533,628.7128,66.3319,637.9106,70.1161,633.7059,74.3208,637.4901,69.8533,628.7128" style="stroke:#383838;stroke-width:1.0;"/><!--MD5=[cdb229abe92fd1672bac6bf302be0a95]
link quantity_kind to quantity_point_kind--><path codeLine="72" d="M443.73,615.157 C401.286,645.525 323.949,700.859 276.264,734.976 " fill="none" id="quantity_kind-to-quantity_point_kind" style="stroke:#383838;stroke-width:1.0;"/><polygon fill="#383838" points="265.4,742.7492,272.6072,742.5112,275.1595,735.7669,267.9523,736.0049,265.4,742.7492" style="stroke:#383838;stroke-width:1.0;"/><!--MD5=[b70cc1f6fe797c95e8c32899ac5bc65f]
@startuml
skinparam monochrome true
skinparam shadowing false
skinparam backgroundColor #fcfcfc
hide circle
hide members
show class methods
package Unit <<Frame>> [[../../framework/units.html]] {
}
package Dimension <<Frame>> [[../../framework/dimensions.html]] {
}
package Kind <<Frame>> [[../../framework/quantity_kinds.html#kind-creation]] {
abstract kind<Dimension> [[../../framework/quantity_kinds.html#kind-creation]]
}
package PointKind <<Frame>> [[../../framework/quantity_kinds.html#quantity-point-kinds]] {
abstract point_kind<Kind, PointOrigin> [[../../framework/quantity_kinds.html#quantity-point-kinds]]
}
package PointOrigin <<Frame>> [[../../framework/quantity_points.html#point-origins]] {
abstract point_origin<Dimension> [[../../framework/quantity_points.html#point-origins]]
}
package Quantity <<Frame>> [[../../framework/quantities.html]] {
class quantity<Dimension, Unit, Rep> [[../../framework/quantities.html#construction]] {
rep number()
}
}
package QuantityPoint <<Frame>> [[../../framework/quantity_points.html]] {
class quantity_point<PointOrigin, Unit, Rep> [[../../framework/quantity_points.html#construction]] {
quantity relative()
}
}
package QuantityKind <<Frame>> [[../../framework/quantity_kinds.html]] {
class quantity_kind<Kind, Unit, Rep> [[../../framework/quantity_kinds.html#construction]] {
quantity common()
}
}
package QuantityPointKind <<Frame>> [[../../framework/quantity_kinds.html#quantity-point-kinds]] {
class quantity_point_kind<PointKind, Unit, Rep> [[../../framework/quantity_kinds.html#quantity-point-kinds]] {
quantity_kind relative()
}
}
Unit <.. Dimension
Dimension <... Quantity
Unit <... Quantity
Dimension <... Kind
Dimension <... PointOrigin
PointOrigin <... PointKind
Kind <... PointKind
Unit <... QuantityPoint
PointOrigin <... QuantityPoint
quantity - -* quantity_point
Unit <... QuantityKind
Kind <... QuantityKind
quantity - -* quantity_kind
Unit <... QuantityPointKind
PointKind <... QuantityPointKind
quantity_kind - -* quantity_point_kind
@enduml
PlantUML version 1.2021.12(Tue Oct 05 16:01:58 UTC 2021)
(GPL source distribution)
Java Runtime: Java(TM) SE Runtime Environment
JVM: Java HotSpot(TM) 64-Bit Server VM
Default Encoding: UTF-8
Language: en
Country: US
--></g></svg>

Before

Width:  |  Height:  |  Size: 27 KiB

View File

@ -1,35 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="256px" preserveAspectRatio="none" style="width:271px;height:256px;background:#FCFCFC;" version="1.1" viewBox="0 0 271 256" width="271px" zoomAndPan="magnify"><defs/><g><!--MD5=[3235af1cc77a6acc457ea7021772201c]
cluster Dimension--><rect fill="#FCFCFC" height="243" style="stroke:#000000;stroke-width:1.5;" width="258" x="7" y="7"/><path d="M101,7 L101,16.2969 L91,26.2969 L7,26.2969 " fill="none" style="stroke:#000000;stroke-width:1.5;"/><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacing" textLength="84" x="10" y="20.9951">Dimension</text><!--MD5=[418e3bda8d8c8b7ad8dc503f3566e869]
class base_dimension--><a href="../../framework/units.html" target="_top" title="../../framework/units.html" xlink:actuate="onRequest" xlink:href="../../framework/units.html" xlink:show="new" xlink:title="../../framework/units.html" xlink:type="simple"><rect codeLine="9" fill="#F8F8F8" height="23.9688" id="base_dimension" style="stroke:#383838;stroke-width:1.5;" width="184" x="44" y="42"/><text fill="#000000" font-family="sans-serif" font-size="12" font-style="italic" lengthAdjust="spacing" textLength="96" x="47" y="58.1387">base_dimension</text><rect fill="#FCFCFC" height="15.9688" style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" width="80" x="151" y="39"/><text fill="#000000" font-family="sans-serif" font-size="12" font-style="italic" lengthAdjust="spacing" textLength="78" x="152" y="51.1387">Symbol, Unit</text></a><!--MD5=[68f31181282be310d7d3efc1882b33d4]
class exponent--><a href="../../framework/dimensions.html#derived-dimensions" target="_top" title="../../framework/dimensions.html#derived-dimensions" xlink:actuate="onRequest" xlink:href="../../framework/dimensions.html#derived-dimensions" xlink:show="new" xlink:title="../../framework/dimensions.html#derived-dimensions" xlink:type="simple"><rect codeLine="10" fill="#F8F8F8" height="23.9688" id="exponent" style="stroke:#383838;stroke-width:1.5;" width="199" x="36.5" y="126"/><text fill="#000000" font-family="sans-serif" font-size="12" font-style="italic" lengthAdjust="spacing" textLength="57" x="39.5" y="142.1387">exponent</text><rect fill="#FCFCFC" height="15.9688" style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" width="134" x="104.5" y="123"/><text fill="#000000" font-family="sans-serif" font-size="12" font-style="italic" lengthAdjust="spacing" textLength="132" x="105.5" y="135.1387">Dimension, Num, Den</text></a><!--MD5=[21e724ef10c67d921f6b3fcb22c06f35]
class derived_dimension--><a href="../../framework/dimensions.html#derived-dimensions" target="_top" title="../../framework/dimensions.html#derived-dimensions" xlink:actuate="onRequest" xlink:href="../../framework/dimensions.html#derived-dimensions" xlink:show="new" xlink:title="../../framework/dimensions.html#derived-dimensions" xlink:type="simple"><rect codeLine="11" fill="#F8F8F8" height="23.9688" id="derived_dimension" style="stroke:#383838;stroke-width:1.5;" width="226" x="23" y="210"/><text fill="#000000" font-family="sans-serif" font-size="12" font-style="italic" lengthAdjust="spacing" textLength="113" x="26" y="226.1387">derived_dimension</text><rect fill="#FCFCFC" height="15.9688" style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" width="105" x="147" y="207"/><text fill="#000000" font-family="sans-serif" font-size="12" font-style="italic" lengthAdjust="spacing" textLength="103" x="148" y="219.1387">Unit, Exponent...</text></a><!--MD5=[a178719c9c6142e046a1431351c96a28]
reverse link base_dimension to exponent--><path codeLine="13" d="M136,71.197 C136,87.356 136,111.751 136,125.854 " fill="none" id="base_dimension-backto-exponent" style="stroke:#383838;stroke-width:1.0;stroke-dasharray:7.0,7.0;"/><polygon fill="#383838" points="136,66.059,132,75.059,136,71.059,140,75.059,136,66.059" style="stroke:#383838;stroke-width:1.0;"/><!--MD5=[cd03d9c68e1638ad57e35f0e1135acfc]
reverse link exponent to derived_dimension--><path codeLine="14" d="M125.605,155.197 C122.073,171.3561 122.514,195.7514 126.928,209.8544 " fill="none" id="exponent-backto-derived_dimension" style="stroke:#383838;stroke-width:1.0;stroke-dasharray:7.0,7.0;"/><polygon fill="#383838" points="126.955,150.059,120.8001,157.7477,125.6849,154.895,128.5377,159.7799,126.955,150.059" style="stroke:#383838;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="24" x="94.2358" y="198.8513">0..n</text><!--MD5=[1f4f10499975d495bfeb71f1fbda2882]
link exponent to derived_dimension--><path codeLine="15" d="M145.577,150.059 C150.268,164.12 150.752,188.5106 147.03,204.7039 " fill="none" id="exponent-to-derived_dimension" style="stroke:#383838;stroke-width:1.0;stroke-dasharray:7.0,7.0;"/><polygon fill="#383838" points="145.606,209.8544,151.859,202.2452,146.938,205.0351,144.1481,200.1141,145.606,209.8544" style="stroke:#383838;stroke-width:1.0;"/><!--MD5=[da6c529a5f75ef54a9908f22b56975b6]
@startuml
skinparam monochrome true
skinparam shadowing false
skinparam backgroundColor #fcfcfc
hide members
hide circle
package Dimension <<Frame>> {
abstract base_dimension<Symbol, Unit> [[../../framework/units.html]]
abstract exponent<Dimension, Num, Den> [[../../framework/dimensions.html#derived-dimensions]]
abstract derived_dimension<Unit, Exponent...> [[../../framework/dimensions.html#derived-dimensions]]
base_dimension <.. exponent
exponent <.. "0..n" derived_dimension
exponent ..> derived_dimension
}
@enduml
PlantUML version 1.2021.12(Tue Oct 05 16:01:58 UTC 2021)
(GPL source distribution)
Java Runtime: Java(TM) SE Runtime Environment
JVM: Java HotSpot(TM) 64-Bit Server VM
Default Encoding: UTF-8
Language: en
Country: US
--></g></svg>

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

View File

@ -1,37 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentStyleType="text/css" height="348px" preserveAspectRatio="none" style="width:288px;height:348px;background:#FCFCFC;" version="1.1" viewBox="0 0 288 348" width="288px" zoomAndPan="magnify"><defs/><g><!--MD5=[da1b011f603b1fa92adce02fc4bac354]
class quantity--><a href="../framework/quantities.html" target="_top" title="../framework/quantities.html" xlink:actuate="onRequest" xlink:href="../framework/quantities.html" xlink:show="new" xlink:title="../framework/quantities.html" xlink:type="simple"><g id="elem_quantity"><rect codeLine="8" fill="#F1F1F1" height="26.2969" id="quantity" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="66" x="80" y="110"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="60" x="83" y="127.9951">quantity</text></g></a><!--MD5=[18fbdc711d33f9ff282e1f4c30c050e6]
class quantity_point--><a href="../framework/quantity_points.html" target="_top" title="../framework/quantity_points.html" xlink:actuate="onRequest" xlink:href="../framework/quantity_points.html" xlink:show="new" xlink:title="../framework/quantity_points.html" xlink:type="simple"><g id="elem_quantity_point"><rect codeLine="9" fill="#F1F1F1" height="26.2969" id="quantity_point" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="112" x="7" y="213"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="106" x="10" y="230.9951">quantity_point</text></g></a><!--MD5=[5b6ab379e9f247363b208f7c72246136]
class quantity_kind--><a href="../framework/quantity_kinds.html" target="_top" title="../framework/quantity_kinds.html" xlink:actuate="onRequest" xlink:href="../framework/quantity_kinds.html" xlink:show="new" xlink:title="../framework/quantity_kinds.html" xlink:type="simple"><g id="elem_quantity_kind"><rect codeLine="10" fill="#F1F1F1" height="26.2969" id="quantity_kind" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="104" x="154" y="213"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="98" x="157" y="230.9951">quantity_kind</text></g></a><!--MD5=[6d322596e71f19471be4dbdd0c5e34a1]
class quantity_point_kind--><a href="../framework/quantity_kinds.html#quantity-point-kinds" target="_top" title="../framework/quantity_kinds.html#quantity-point-kinds" xlink:actuate="onRequest" xlink:href="../framework/quantity_kinds.html#quantity-point-kinds" xlink:show="new" xlink:title="../framework/quantity_kinds.html#quantity-point-kinds" xlink:type="simple"><g id="elem_quantity_point_kind"><rect codeLine="11" fill="#F1F1F1" height="26.2969" id="quantity_point_kind" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="150" x="131" y="316"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="144" x="134" y="333.9951">quantity_point_kind</text></g></a><!--MD5=[b2a694e6474a2a9b22a2e31fbfd4909a]
class Rep--><g id="elem_Rep"><rect fill="#F1F1F1" height="26.2969" id="Rep" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="35" x="95.5" y="7"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="29" x="98.5" y="24.9951">Rep</text></g><!--MD5=[e24fe1f9fefda9999290bb447fae99e3]
reverse link Rep to quantity--><g id="link_Rep_quantity"><path codeLine="13" d="M113,38.526 C113,58.92 113,92.061 113,109.83 " fill="none" id="Rep-backto-quantity" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="113,33.385,109,42.385,113,38.385,117,42.385,113,33.385" style="stroke:#181818;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="60" x="114" y="76.0669">number()</text></g><!--MD5=[90d8d95e9adcc8fc2f6906e762b4a14d]
reverse link quantity to quantity_point--><g id="link_quantity_quantity_point"><path codeLine="14" d="M98.633,140.033 C92.5205,147.508 85.7271,156.776 81,166 C73.1851,181.249 68.1076,200.483 65.3984,212.765 " fill="none" id="quantity-backto-quantity_point" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="101.9413,136.076,93.0996,140.4147,98.7341,139.9118,99.2369,145.5463,101.9413,136.076" style="stroke:#181818;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="58" x="82" y="179.0669">relative()</text></g><!--MD5=[dd075b90f0ec4f5db24762fad9b93a06]
reverse link quantity to quantity_kind--><g id="link_quantity_quantity_kind"><path codeLine="15" d="M127.956,140.242 C146.612,160.503 178.084,194.683 194.794,212.83 " fill="none" id="quantity-backto-quantity_kind" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="124.404,136.385,127.5577,145.7153,127.7908,140.0632,133.4429,140.2964,124.404,136.385" style="stroke:#181818;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="67" x="167" y="179.0669">common()</text></g><!--MD5=[1acbd4671b34e1d8b20d7848e474454e]
reverse link quantity_kind to quantity_point_kind--><g id="link_quantity_kind_quantity_point_kind"><path codeLine="16" d="M206,244.5264 C206,264.9203 206,298.0611 206,315.8296 " fill="none" id="quantity_kind-backto-quantity_point_kind" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="206,239.385,202,248.385,206,244.385,210,248.385,206,239.385" style="stroke:#181818;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="58" x="207" y="282.0669">relative()</text></g><!--MD5=[abc9f5195c71d2db961c2d927d457aba]
@startuml
skinparam monochrome true
skinparam shadowing false
skinparam backgroundColor #fcfcfc
hide members
hide circle
class quantity [[../framework/quantities.html]]
class quantity_point [[../framework/quantity_points.html]]
class quantity_kind [[../framework/quantity_kinds.html]]
class quantity_point_kind [[../framework/quantity_kinds.html#quantity-point-kinds]]
Rep <- - quantity : number()
quantity <- - quantity_point : relative()
quantity <- - quantity_kind : common()
quantity_kind <- - quantity_point_kind : relative()
@enduml
PlantUML version 1.2022.6beta5(Unknown compile time)
(GPL source distribution)
Java Runtime: Java(TM) SE Runtime Environment
JVM: Java HotSpot(TM) 64-Bit Server VM
Default Encoding: UTF-8
Language: en
Country: US
--></g></svg>

Before

Width:  |  Height:  |  Size: 6.4 KiB

View File

@ -1,158 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentStyleType="text/css" height="456px" preserveAspectRatio="none" style="width:591px;height:456px;background:#FCFCFC;" version="1.1" viewBox="0 0 591 456" width="591px" zoomAndPan="magnify">
<defs />
<g>
<!--MD5=[197a77df23d290968e58c76a2239d979]
cluster Unit-->
<g id="cluster_Unit">
<a href="../../framework/units.html" target="_top" title="../../framework/units.html" xlink:actuate="onRequest" xlink:href="../../framework/units.html" xlink:show="new" xlink:title="../../framework/units.html" xlink:type="simple">
<rect height="443" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:1.0;fill:none;" width="578" x="7" y="7" />
<path d="M51,7 L51,16.2969 L41,26.2969 L7,26.2969 " fill="none" style="stroke:#181818;stroke-width:1.0;" />
<text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacing" textLength="34" x="10" y="20.9951">Unit</text>
</a>
</g> <!--MD5=[124cbcdfdb408a63d08476bd52d3bb38]
class scaled_unit-->
<g id="elem_scaled_unit">
<rect codeLine="12" fill="#F1F1F1" height="26.2969" id="scaled_unit" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="178" x="23" y="225" />
<text fill="#000000" font-family="sans-serif" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="80" x="26" y="242.9951">scaled_unit</text>
<rect fill="#FCFCFC" height="15.9688" style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" width="90" x="114" y="222" />
<text fill="#000000" font-family="sans-serif" font-size="12" font-style="italic" lengthAdjust="spacing" textLength="88" x="115" y="234.1387">UnitRatio, Unit</text>
</g> <!--MD5=[c262fc293e71d96455ecd38c5cba51e9]
class prefixed_alias_unit-->
<a href="../../framework/units.html#aliased-units" target="_top" title="../../framework/units.html#aliased-units" xlink:actuate="onRequest" xlink:href="../../framework/units.html#aliased-units" xlink:show="new" xlink:title="../../framework/units.html#aliased-units" xlink:type="simple">
<g id="elem_prefixed_alias_unit">
<rect codeLine="14" fill="#F1F1F1" height="26.2969" id="prefixed_alias_unit" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="269" x="280.5" y="408" />
<text fill="#000000" font-family="sans-serif" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="133" x="283.5" y="425.9951">prefixed_alias_unit</text>
<rect fill="#FCFCFC" height="15.9688" style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" width="128" x="424.5" y="405" />
<text fill="#000000" font-family="sans-serif" font-size="12" font-style="italic" lengthAdjust="spacing" textLength="126" x="425.5" y="417.1387">Unit, Prefix, AliasUnit</text>
</g>
</a> <!--MD5=[80b1f1fe027b66c9bd530ac9502a064a]
class alias_unit-->
<a href="../../framework/units.html#aliased-units" target="_top" title="../../framework/units.html#aliased-units" xlink:actuate="onRequest" xlink:href="../../framework/units.html#aliased-units" xlink:show="new" xlink:title="../../framework/units.html#aliased-units" xlink:type="simple">
<g id="elem_alias_unit">
<rect codeLine="15" fill="#F1F1F1" height="26.2969" id="alias_unit" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="155" x="337.5" y="347" />
<text fill="#000000" font-family="sans-serif" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="67" x="340.5" y="364.9951">alias_unit</text>
<rect fill="#FCFCFC" height="15.9688" style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" width="80" x="415.5" y="344" />
<text fill="#000000" font-family="sans-serif" font-size="12" font-style="italic" lengthAdjust="spacing" textLength="78" x="416.5" y="356.1387">Unit, Symbol</text>
</g>
</a> <!--MD5=[26e0af737c6dfe4c6ad8ee7c79493d2e]
class derived_scaled_unit-->
<a href="../../framework/units.html#derived-scaled-units" target="_top" title="../../framework/units.html#derived-scaled-units" xlink:actuate="onRequest" xlink:href="../../framework/units.html#derived-scaled-units" xlink:show="new" xlink:title="../../framework/units.html#derived-scaled-units" xlink:type="simple">
<g id="elem_derived_deduced_unit">
<rect codeLine="16" fill="#F1F1F1" height="26.2969" id="derived_scaled_unit" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="308" x="261" y="286" />
<text fill="#000000" font-family="sans-serif" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="157" x="264" y="303.9951">derived_scaled_unit</text>
<rect fill="#FCFCFC" height="15.9688" style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" width="143" x="429" y="283" />
<text fill="#000000" font-family="sans-serif" font-size="12" font-style="italic" lengthAdjust="spacing" textLength="141" x="430" y="295.1387">Dimension, Unit, Unit...</text>
</g>
</a> <!--MD5=[21a38f8b465de3a6a580896bb83abf03]
class derived_unit-->
<a href="../../framework/units.html#derived-unnamed-units" target="_top" title="../../framework/units.html#derived-unnamed-units" xlink:actuate="onRequest" xlink:href="../../framework/units.html#derived-unnamed-units" xlink:show="new" xlink:title="../../framework/units.html#derived-unnamed-units" xlink:type="simple">
<g id="elem_derived_unit">
<rect codeLine="17" fill="#F1F1F1" height="26.2969" id="derived_unit" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="94" x="368" y="225" />
<text fill="#000000" font-family="sans-serif" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="88" x="371" y="242.9951">derived_unit</text>
</g>
</a> <!--MD5=[002996a525ad7ee43e1a2ae0bbb7adb6]
class prefixed_unit-->
<a href="../../framework/units.html#prefixed-unit" target="_top" title="../../framework/units.html#prefixed-unit" xlink:actuate="onRequest" xlink:href="../../framework/units.html#prefixed-unit" xlink:show="new" xlink:title="../../framework/units.html#prefixed-unit" xlink:type="simple">
<g id="elem_prefixed_unit">
<rect codeLine="18" fill="#F1F1F1" height="26.2969" id="prefixed_unit" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="169" x="330.5" y="164" />
<text fill="#000000" font-family="sans-serif" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="93" x="333.5" y="181.9951">prefixed_unit</text>
<rect fill="#FCFCFC" height="15.9688" style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" width="68" x="434.5" y="161" />
<text fill="#000000" font-family="sans-serif" font-size="12" font-style="italic" lengthAdjust="spacing" textLength="66" x="435.5" y="173.1387">Prefix, Unit</text>
</g>
</a> <!--MD5=[3a0c8cf47fc662100af5bce8b7f7e204]
class named_scaled_unit-->
<a href="../../framework/units.html#named-scaled-units" target="_top" title="../../framework/units.html#named-scaled-units" xlink:actuate="onRequest" xlink:href="../../framework/units.html#named-scaled-units" xlink:show="new" xlink:title="../../framework/units.html#named-scaled-units" xlink:type="simple">
<g id="elem_named_scaled_unit">
<rect codeLine="19" fill="#F1F1F1" height="26.2969" id="named_scaled_unit" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="263" x="283.5" y="103" />
<text fill="#000000" font-family="sans-serif" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="137" x="286.5" y="120.9951">named_scaled_unit</text>
<rect fill="#FCFCFC" height="15.9688" style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" width="118" x="431.5" y="100" />
<text fill="#000000" font-family="sans-serif" font-size="12" font-style="italic" lengthAdjust="spacing" textLength="116" x="432.5" y="112.1387">Symbol, Ratio, Unit</text>
</g>
</a> <!--MD5=[5e57872b30d77ee0da3206dd3d117986]
class named_unit-->
<a href="../../framework/units.html#base-units" target="_top" title="../../framework/units.html#base-units" xlink:actuate="onRequest" xlink:href="../../framework/units.html#base-units" xlink:show="new" xlink:title="../../framework/units.html#base-units" xlink:type="simple">
<g id="elem_named_unit">
<rect codeLine="20" fill="#F1F1F1" height="26.2969" id="named_unit" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="139" x="345.5" y="42" />
<text fill="#000000" font-family="sans-serif" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="84" x="348.5" y="59.9951">named_unit</text>
<rect fill="#FCFCFC" height="15.9688" style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" width="47" x="440.5" y="39" />
<text fill="#000000" font-family="sans-serif" font-size="12" font-style="italic" lengthAdjust="spacing" textLength="45" x="441.5" y="51.1387">Symbol</text>
</g>
</a> <!--MD5=[d10f3427b03caf67d8b4e569e5f4936e]
reverse link scaled_unit to named_unit-->
<g id="link_scaled_unit_named_unit">
<path codeLine="22" d="M133.027,208.194 C158.437,172.883 205.676,115.067 261,85 C286.686,71.041 317.93,63.52 345.471,59.49 " fill="none" id="scaled_unit-backto-named_unit" style="stroke:#181818;stroke-width:1.0;" />
<polygon fill="none" points="138.679,212.326,121.521,224.76,127.181,204.34,138.679,212.326" style="stroke:#181818;stroke-width:1.0;" />
</g> <!--MD5=[c4573f7b87c3262f7d3adc92106a39ed]
reverse link scaled_unit to named_scaled_unit-->
<g id="link_scaled_unit_named_scaled_unit">
<path codeLine="23" d="M145.911,212.637 C174.734,191.666 218.536,162.71 261,146 C279.262,138.814 299.451,133.292 319.011,129.068 " fill="none" id="scaled_unit-backto-named_scaled_unit" style="stroke:#181818;stroke-width:1.0;" />
<polygon fill="none" points="149.884,218.407,129.672,224.769,141.505,207.191,149.884,218.407" style="stroke:#181818;stroke-width:1.0;" />
</g> <!--MD5=[65b74da07c0359a7bcc888d9c9b6e7d5]
reverse link scaled_unit to prefixed_unit-->
<g id="link_scaled_unit_prefixed_unit">
<path codeLine="24" d="M194.254,220.784 C215.93,216.246 239.344,211.391 261,207 C288.988,201.325 319.892,195.233 346.556,190.03 " fill="none" id="scaled_unit-backto-prefixed_unit" style="stroke:#181818;stroke-width:1.0;" />
<polygon fill="none" points="195.542,227.667,174.53,224.927,192.664,213.966,195.542,227.667" style="stroke:#181818;stroke-width:1.0;" />
</g> <!--MD5=[29a2e6b65a8256359df6b41e4d3b7c7c]
reverse link scaled_unit to derived_unit-->
<g id="link_scaled_unit_derived_unit">
<path codeLine="25" d="M221.579,238 C271.79,238 328.764,238 367.604,238 " fill="none" id="scaled_unit-backto-derived_unit" style="stroke:#181818;stroke-width:1.0;" />
<polygon fill="none" points="221.276,245,201.276,238,221.276,231,221.276,245" style="stroke:#181818;stroke-width:1.0;" />
</g> <!--MD5=[1916bf928027667941dfca121ed1aff3]
reverse link scaled_unit to derived_scaled_unit-->
<g id="link_scaled_unit_derived_deduced_unit">
<path codeLine="26" d="M197.3,255.089 C218.121,259.31 240.369,263.819 261,268 C290.086,273.894 322.282,280.418 349.606,285.954 " fill="none" id="scaled_unit-backto-derived_scaled_unit" style="stroke:#181818;stroke-width:1.0;" />
<polygon fill="none" points="195.683,261.904,177.472,251.07,198.464,248.183,195.683,261.904" style="stroke:#181818;stroke-width:1.0;" />
</g> <!--MD5=[19d99332ae619b76851ceaa34f4e9014]
reverse link scaled_unit to alias_unit-->
<g id="link_scaled_unit_alias_unit">
<path codeLine="27" d="M145.982,263.005 C174.849,283.698 218.676,312.311 261,329 C285.078,338.494 312.484,345.219 337.384,349.919 " fill="none" id="scaled_unit-backto-alias_unit" style="stroke:#181818;stroke-width:1.0;" />
<polygon fill="none" points="141.677,268.529,129.714,251.039,149.972,257.251,141.677,268.529" style="stroke:#181818;stroke-width:1.0;" />
</g> <!--MD5=[a61d68e6008f4d1392d92030b50774f1]
reverse link scaled_unit to prefixed_alias_unit-->
<g id="link_scaled_unit_prefixed_alias_unit">
<path codeLine="28" d="M133.104,267.552 C158.592,302.572 205.908,359.952 261,390 C275.157,397.7215 290.998,403.5283 306.976,407.8934 " fill="none" id="scaled_unit-backto-prefixed_alias_unit" style="stroke:#181818;stroke-width:1.0;" />
<polygon fill="none" points="127.332,271.513,121.559,251.125,138.786,263.462,127.332,271.513" style="stroke:#181818;stroke-width:1.0;" />
</g> <!--MD5=[f18d7856f7539404df991684234dc7ed]
@startuml
skinparam monochrome true
skinparam shadowing false
skinparam backgroundColor #fcfcfc
hide members
hide circle
left to right direction
package Unit <<Frame>> [[../../framework/units.html]] {
abstract scaled_unit<UnitRatio, Unit>
abstract prefixed_alias_unit<Unit, Prefix, AliasUnit> [[../../framework/units.html#aliased-units]]
abstract alias_unit<Unit, Symbol> [[../../framework/units.html#aliased-units]]
abstract derived_scaled_unit<Dimension, Unit, Unit...> [[../../framework/units.html#derived-scaled-units]]
abstract derived_unit [[../../framework/units.html#derived-unnamed-units]]
abstract prefixed_unit<Prefix, Unit> [[../../framework/units.html#prefixed-unit]]
abstract named_scaled_unit<Symbol, Ratio, Unit> [[../../framework/units.html#named-scaled-units]]
abstract named_unit<Symbol> [[../../framework/units.html#base-units]]
scaled_unit <|- - named_unit
scaled_unit <|- - named_scaled_unit
scaled_unit <|- - prefixed_unit
scaled_unit <|- - derived_unit
scaled_unit <|- - derived_scaled_unit
scaled_unit <|- - alias_unit
scaled_unit <|- - prefixed_alias_unit
}
@enduml
PlantUML version 1.2022.5(Sat Apr 30 10:55:52 UTC 2022)
(GPL source distribution)
Java Runtime: Java(TM) SE Runtime Environment
JVM: Java HotSpot(TM) 64-Bit Server VM
Default Encoding: UTF-8
Language: en
Country: US
-->
</g>
</svg>

Before

Width:  |  Height:  |  Size: 14 KiB

View File

View File

@ -0,0 +1 @@
../../CHANGELOG.md

View File

@ -1,139 +0,0 @@
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options.
# For a full list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
import re
def get_version():
try:
with open("../src/CMakeLists.txt", "r") as file:
content = file.read()
version = re.search(
r"project\([^\)]+VERSION (\d+\.\d+\.\d+)[^\)]*\)", content
).group(1)
return version.strip()
except Exception:
return None
# -- Project information -----------------------------------------------------
project = "mp-units"
copyright = "2018-present, Mateusz Pusz"
author = "Mateusz Pusz"
# The major project version, used as the replacement for |version|.
version = get_version()
# The full project version, used as the replacement for |release| and
# e.g. in the HTML templates.
release = get_version()
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
"sphinx.ext.autosectionlabel",
"sphinx.ext.githubpages",
"sphinx.ext.graphviz",
"sphinx_rtd_theme",
"recommonmark",
"breathe",
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
# If true, Sphinx will warn about all references where the target cannot
# be found. Default is False.
nitpicky = True
# A list of (type, target) tuples (by default empty) that should be ignored
# when generating warnings in “nitpicky mode”. Note that type should include
# the domain name if present. Example entries would be ('py:func', 'int')
# or ('envvar', 'LD_LIBRARY_PATH').
nitpick_ignore = []
# True to prefix each section label with the name of the document it is in,
# followed by a colon. Useful for avoiding ambiguity when the same section
# heading appears in different documents.
autosectionlabel_prefix_document = True
# -- C++ configuration ---------------------------------------------------
# The name of the default domain. Can also be None to disable a default
# domain. The default is 'py'.
primary_domain = "cpp"
# The reST default role (used for this markup: `text`) to use for all documents.
default_role = "cpp:any"
# The default language to highlight source code in. The default is 'python3'.
# The value should be a valid Pygments lexer name (https://pygments.org/docs/lexers).
highlight_language = "cpp"
# The style name to use for Pygments highlighting of source code. If not set,
# either the themes default style or 'sphinx' is selected for HTML output.
pygments_style = "default"
# A list of prefixes that will be ignored when sorting C++ objects in the global
# index. For example ['awesome_lib::'].
cpp_index_common_prefix = ["units::"]
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = "sphinx_rtd_theme"
# A dictionary of options that influence the look and feel of the selected theme.
# These are theme-specific.
html_theme_options = {
# WARNING: unsupported theme option 'github_url' given
# 'github_url': 'https://github.com/mpusz/units'
}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ["_static"]
# If given, this must be the name of an image file (path relative to the
# configuration directory) that is the logo of the docs. It is placed at the
# top of the sidebar; its width should therefore not exceed 200 pixels.
# Default: None.
# html_logo =
# These paths are either relative to html_static_path or fully qualified
# paths (eg. https://...)
html_css_files = ["css/custom.css"]
# -- Breathe configuration ---------------------------------------------------
# This should be a dictionary in which the keys are project names and the values
# are paths to the folder containing the doxygen output for that project.
breathe_projects = {"mp-units": "build/xml"}
# This should match one of the keys in the breathe_projects dictionary and
# indicates which project should be used when the project is not specified on
# the directive.
breathe_default_project = "mp-units"
# Allows you to specify domains for particular files according to their extension.
breathe_domain_by_extension = {"h": "cpp"}
# Provides the directive flags that should be applied to all directives which
# take :members:, :private-members: and :undoc-members: options. By default,
# this is set to an empty list, which means no members are displayed.
breathe_default_members = ("members",)

View File

@ -1,9 +0,0 @@
Defining Systems
================
.. toctree::
:maxdepth: 2
defining_systems/isq
defining_systems/si
defining_systems/angular_units

View File

@ -1,175 +0,0 @@
.. namespace:: units
Angular Units
=============
Some background information
---------------------------
As per today's SI, both radian and steradian are dimensionless. This forces the convention to set the angle ``1 radian``
equal to the number ``1`` within equations (similar to what natural units system does for ``c`` constant).
Following `Wikipedia <https://en.wikipedia.org/wiki/Radian#Dimensional_analysis>`_:
Giacomo Prando says "the current state of affairs leads inevitably to ghostly appearances and disappearances of the radian
in the dimensional analysis of physical equations." For example, a mass hanging by a string from a pulley will rise or drop
by :math:`y=rθ`` centimeters, where :math:`r` is the radius of the pulley in centimeters and :math:`θ` is the angle
the pulley turns in radians. When multiplying :math:`r` by :math:`θ` the unit of radians disappears from the result.
Similarly in the formula for the angular velocity of a rolling wheel, :math:`ω=v/r`, radians appear in the units of
:math:`ω` but not on the right hand side.
Anthony French calls this phenomenon "a perennial problem in the teaching of mechanics". Oberhofer says that the typical
advice of ignoring radians during dimensional analysis and adding or removing radians in units according to convention
and contextual knowledge is "pedagogically unsatisfying".
At least a dozen scientists have made proposals to treat the radian as a base unit of measure defining its own dimension of "angle",
as early as 1936 and as recently as 2022. This would bring the advantages of a physics-based, consistent, and logically-robust
unit system, with unambiguous units for all physical quantities. At the same time the only notable changes for typical
end-users would be: improved units for the quantities **torque**, **angular momentum** and **moment of inertia**.
Paul Quincey in his proposal *"Angles in the SI: a detailed proposal for solving the problem"* [Quincey]_ states:
The familiar units assigned to some angular quantities are based on equations that have adopted the radian convention,
and so are missing `rad`s that would be present if the complete equation is used. The physically-correct units are
those with the `rad`s reinstated. Numerical values would not change, and the physical meanings of all quantities would
also be unaffected.
He proposes the following changes:
- The **radian** would become either a new base unit or a 'complementary' unit
- The **steradian** would become a derived unit equal to :math:`1\:rad^2`
- The SI units for
- **Torque** would change from :math:`N\:m` (= J) to :math:`J\:rad^{-1}`
- **Angular momentum** would change from :math:`J\:s` to :math:`J\:s\:rad^{-1}` (i.e. :math:`J/(rad/s)`)
- **Moment of inertia** would change from :math:`kg\:m^2` to :math:`kg\:m^2\:rad^{-2}` (i.e. :math:`J/(rad/s)^2`)
- The option to omit the radian from the SI units for **angle**, **angular velocity**, **angular frequency**,
**angular acceleration**, and **angular wavenumber** would be removed, the only correct SI units being
:math:`rad`, :math:`rad/s`, :math:`rad/s`, :math:`rad/s^2` and :math:`rad/m` respectively.
Paul Quincey summarizes that with the above in action:
However, the physical clarity this would build into the SI should be recognised very quickly. The units would tell us that
:math:`torque \times angle = energy`, and :math:`angular\:momentum \times angle = action`, for example, in the same way that they do for
:math:`force \times distance = energy`, :math:`linear\:momentum \times distance = action`, and
:math:`radiant\:intensity \times solid\:angle = radiant\:flux`.
Dimensional analysis could be used to its full extent. Software involving angular quantities would be rationalised.
Arguments about the correct units for frequency and angular frequency, and the meaning of the unit Hz, could be left behind.
The explanation of these changes would be considerably easier and more rewarding than explaining how a kilogram-sized mass
can be measured in terms of the Planck constant.
Angular quantities in the :term:`SI`
------------------------------------
Even though the :term:`SI` somehow ignores the dimensionality of angle:
Plane and solid angles, when expressed in radians and steradians respectively, are in effect
also treated within the SI as quantities with the unit one. The symbols :math:`rad`
and :math:`sr` are written explicitly where appropriate, in order to emphasize that, for radians or
steradians, the quantity being considered is, or involves the plane angle or solid angle
respectively. For steradians it emphasizes the distinction between units of flux and intensity
in radiometry and photometry for example. However, it is a long-established practice in
mathematics and across all areas of science to make use of :math:`rad = 1` and :math:`sr = 1`.
For historical reasons the radian and steradian are treated as derived units.
It also explicitly states:
The SI unit of frequency is hertz, the SI unit of angular velocity and angular frequency is
radian per second, and the SI unit of activity is becquerel, implying counts per second.
Although it is formally correct to write all three of these units as the reciprocal second, the
use of the different names emphasizes the different nature of the quantities concerned. It is
especially important to carefully distinguish frequencies from angular frequencies, because
by definition their numerical values differ by a factor of :math:`2\pi`. Ignoring this fact may cause
an error of :math:`2\pi`. Note that in some countries, frequency values are conventionally expressed
using “cycle/s” or “cps” instead of the SI unit :math:`Hz`, although “cycle” and “cps” are not units
in the SI. Note also that it is common, although not recommended, to use the term
frequency for quantities expressed in :math:`rad/s`. Because of this, it is recommended that
quantities called “frequency”, “angular frequency”, and “angular velocity” always be given
explicit units of :math:`Hz` or :math:`rad/s`` and not :math:`s^{-1}`.
Angular quantities in the library
---------------------------------
The mp-units library strives to define physically-correct quantities and their units to provide maximum help
to its users. As treating angle as a dimensional quantity can lead to many "trivial" mistakes in dimensional
analysis and calculation, it was decided to follow the above approach and treat angle as a base quantity
with a base unit of radian and solid angle as its derived quantity.
As those the above (at least for now) not a part of :term:`SI`, the plain angle and solid
angle definitions can be found in the *units/generic* subdirectory. However, in the sake of correctness,
they are consistently used in the dimensional recipes of all angle-based :term:`SI` quantities like
torque or angular velocity::
#include <units/generic/angle.h>
#include <units/isq/si/torque.h>
#include <units/math.h>
#include <units/quantity_io.h>
#include <iostream>
int main()
{
using namespace units;
using namespace units::isq;
using namespace units::aliases;
using namespace units::aliases::isq::si;
const Length auto lever = cm<>(20);
const Force auto force = N<>(500);
const Angle auto angle = deg<>(90);
const Torque auto torque = lever * force * sin(angle) / cotes_angle<>;
std::cout << "Applying a perpendicular force of " << force << " to a "
<< lever << " long lever results in "
<< quantity_cast<si::newton_metre_per_radian>(torque) << " of torque.\n";
}
The above program prints:
.. code-block::
Applying a perpendicular force of 500 N to a 20 cm long lever results in 100 N⋅m/rad of torque.
.. note::
`cotes_angle` is a constant which represents an angle with the value of exactly ``1 radian``.
You can find more information about this constant in [Quincey]_.
Radians and degrees support
---------------------------
Thanks to :ref:`framework/magnitudes:Magnitudes` usage the library provides efficient strong types for all
angular types. This means that with the built-in support for magnitudes of :math:`\pi` we can provide
accurate conversions between radians and degrees. The library also provides common trigonometric functions
for angular quantities::
using namespace units::aliases::isq::si;
auto velocity = km_per_h<>(110);
auto rate_of_climb = m_per_s<>(-0.63657);
auto glide_ratio = velocity / -rate_of_climb;
auto glide_angle = asin(1 / glide_ratio);
std::cout << std::format("Glide ratio: {:%.1Q %q}\n", quantity_cast<units::one>(glide_ratio));
std::cout << "Glide angle:\n";
std::cout << std::format(" - {:%.4Q %q}\n", glide_angle);
std::cout << std::format(" - {:%.2Q %q}\n", quantity_cast<units::degree>(glide_angle));
std::cout << std::format(" - {:%.2Q %q}\n", quantity_cast<units::gradian>(glide_angle));
The above program prints:
.. code-block::
Glide ratio: 48.0
Glide angle:
- 0.0208 rad
- 1.19 °
- 1.33 ᵍ
.. note::
The above ``velocity`` and ``rate_of_climb`` in the production code should be modelled as
:ref:`framework/quantity_kinds:Quantity Kinds`.
A better but longer code can be found in the :ref:`examples/basics/glide_computer:glide_computer` example.

View File

@ -1,48 +0,0 @@
.. namespace:: units
International System of Quantities (ISQ)
========================================
According to [ISO80000]_:
The system of quantities, including the relations among them the quantities used as the basis of the units of
the SI, is named the **International System of Quantities**, denoted "ISQ", in all languages.
Base dimensions and their symbols
---------------------------------
According to the [SIBrochure]_:
Physical quantities can be organized in a system of dimensions, where the system used is
decided by convention. Each of the seven base quantities used in the SI is regarded as
having its own dimension. The symbols used for the base quantities and the symbols used
to denote their dimension are shown in Table 3.
Following that the library provides the following definitions::
namespace units::isq {
template<Unit U> struct dim_time : base_dimension<"T", U> {};
template<Unit U> struct dim_length : base_dimension<"L", U> {};
template<Unit U> struct dim_mass : base_dimension<"M", U> {};
template<Unit U> struct dim_electric_current : base_dimension<"I", U> {};
template<Unit U> struct dim_thermodynamic_temperature : base_dimension<"Θ", U> {};
template<Unit U> struct dim_amount_of_substance : base_dimension<"N", U> {};
template<Unit U> struct dim_luminous_intensity : base_dimension<"J", U> {};
}
Base dimension symbols provided above are consistently defined by both [SIBrochure]_ and [ISO80000]_.
Derived dimensions
------------------
[SIBrochure]_ states:
Since the number of quantities is without limit, it is not possible to
provide a complete list of derived quantities and derived units.
The authors of this library decided to limit the set of defined quantities to all
quantities defined in the [ISO80000]_ series of documents.

View File

@ -1,231 +0,0 @@
.. namespace:: units
The International System of Units (SI)
======================================
The :term:`SI` system is defined in the [SIBrochure]_ and standardizes units for quantities provided in
the :term:`ISQ` system:
The SI is a consistent system of units for use in all aspects of life, including international
trade, manufacturing, security, health and safety, protection of the environment, and in the
basic science that underpins all of these. The system of quantities underlying the SI and the
equations relating them are based on the present description of nature and are familiar to all
scientists, technologists and engineers.
As the :term:`SI` is defined on top of the :term:`ISQ` the C++ namespace for all of its definitions
is ``units::isq::si``.
Base units
----------
Even though from 2019 the :term:`SI` system is defined in terms of the `Defining constants`_,
base units still are really important. As the [SIBrochure]_ states:
Prior to the definitions adopted in 2018, the SI was defined through seven base units from
which the derived units were constructed as products of powers of the base units. Defining
the SI by fixing the numerical values of seven defining constants has the effect that this
distinction is, in principle, not needed, since all units, base as well as derived units, may be
constructed directly from the defining constants. Nevertheless, the concept of base and
derived units is maintained because it is useful and historically well established, noting
also that the ISO/IEC 80000 series of Standards specify base and derived quantities which
necessarily correspond to the SI base and derived units defined here.
The base units and quantities of the :term:`SI` system are defined as follows::
namespace units::isq::si {
struct second : named_unit<second, "s"> {};
struct dim_time : isq::dim_time<second> {};
template<UnitOf<dim_time> U, Representation Rep = double>
using time = quantity<dim_time, U, Rep>;
struct metre : named_unit<metre, "m"> {};
struct dim_length : isq::dim_length<metre> {};
template<UnitOf<dim_length> U, Representation Rep = double>
using length = quantity<dim_length, U, Rep>;
struct gram : named_unit<gram, "g"> {};
struct kilogram : prefixed_unit<kilogram, kilo, gram> {};
struct dim_mass : isq::dim_mass<kilogram> {};
template<UnitOf<dim_mass> U, Representation Rep = double>
using mass = quantity<dim_mass, U, Rep>;
struct ampere : named_unit<ampere, "A"> {};
struct dim_electric_current : isq::dim_electric_current<ampere> {};
template<UnitOf<dim_electric_current> U, Representation Rep = double>
using electric_current = quantity<dim_electric_current, U, Rep>;
struct kelvin : named_unit<kelvin, "K"> {};
struct dim_thermodynamic_temperature : isq::dim_thermodynamic_temperature<kelvin> {};
template<UnitOf<dim_thermodynamic_temperature> U, Representation Rep = double>
using thermodynamic_temperature = quantity<dim_thermodynamic_temperature, U, Rep>;
struct mole : named_unit<mole, "mol"> {};
struct dim_amount_of_substance : isq::dim_amount_of_substance<mole> {};
template<UnitOf<dim_amount_of_substance> U, Representation Rep = double>
using amount_of_substance = quantity<dim_amount_of_substance, U, Rep>;
struct candela : named_unit<candela, "cd"> {};
struct dim_luminous_intensity : isq::dim_luminous_intensity<candela> {};
template<UnitOf<dim_luminous_intensity> U, Representation Rep = double>
using luminous_intensity = quantity<dim_luminous_intensity, U, Rep>;
}
Derived units
-------------
The [SIBrochure]_ states:
Derived units are defined as products of powers of the base units. When the numerical
factor of this product is one, the derived units are called coherent derived units. The base
and coherent derived units of the SI form a coherent set, designated the set of coherent SI
units. The word “coherent” here means that equations between the numerical values of
quantities take exactly the same form as the equations between the quantities themselves.
Some of the coherent derived units in the SI are given special names. ... Together with the
seven base units they form the core of the set of SI units. All other SI units are combinations
of some of these 29 units.
Unit prefixes
-------------
According to [SIBrochure]_:
Prefixes may be used with any of the 29 SI units with special names with
the exception of the base unit kilogram.
Here is a complete list of all the :term:`SI` prefixes supported by the library::
namespace si {
struct yocto : prefix<yocto, "y", mag_power<10, -24>()> {};
struct zepto : prefix<zepto, "z", mag_power<10, -21>()> {};
struct atto : prefix<atto, "a", mag_power<10, -18>()> {};
struct femto : prefix<femto, "f", mag_power<10, -15>()> {};
struct pico : prefix<pico, "p", mag_power<10, -12>()> {};
struct nano : prefix<nano, "n", mag_power<10, -9>()> {};
struct micro : prefix<micro, basic_symbol_text{"\u00b5", "u"},
mag_power<10, -6>()> {};
struct milli : prefix<milli, "m", mag_power<10, -3>()> {};
struct centi : prefix<centi, "c", mag_power<10, -2>()> {};
struct deci : prefix<deci, "d", mag_power<10, -1>()> {};
struct deca : prefix<deca, "da", mag_power<10, 1>()> {};
struct hecto : prefix<hecto, "h", mag_power<10, 2>()> {};
struct kilo : prefix<kilo, "k", mag_power<10, 3>()> {};
struct mega : prefix<mega, "M", mag_power<10, 6>()> {};
struct giga : prefix<giga, "G", mag_power<10, 9>()> {};
struct tera : prefix<tera, "T", mag_power<10, 12>()> {};
struct peta : prefix<peta, "P", mag_power<10, 15>()> {};
struct exa : prefix<exa, "E", mag_power<10, 18>()> {};
struct zetta : prefix<zetta, "Z", mag_power<10, 21>()> {};
struct yotta : prefix<yotta, "Y", mag_power<10, 24>()> {};
}
Other definitions for names units
---------------------------------
For all of the above units the library also provides:
- prefixed versions using SI prefixes::
namespace units::isq::si {
struct millisecond : prefixed_unit<millisecond, milli, second> {};
}
- :ref:`framework/quantities:Quantity References (Experimental)`::
namespace units::isq::si {
namespace time_references {
inline constexpr auto s = reference<dim_time, second>{};
}
namespace references {
using namespace time_references;
}
- :ref:`framework/quantities:Unit-Specific Aliases (Experimental)`::
namespace units::aliases::isq::si::inline time {
template<Representation Rep = double>
using s = units::isq::si::time<units::isq::si::second, Rep>;
}
- :ref:`framework/quantities:User Defined Literals (Experimental)`::
namespace units::isq::si::inline literals {
constexpr auto operator"" _q_s(unsigned long long l)
{
gsl_ExpectsAudit(std::in_range<std::int64_t>(l));
return time<second, std::int64_t>(static_cast<std::int64_t>(l));
}
constexpr auto operator"" _q_s(long double l) { return time<second, long double>(l); }
}
For some of the units, when accepted by the :term:`SI`, other non-standard scaled versions are also provided::
namespace units::isq::si {
struct minute : named_scaled_unit<minute, "min", mag<60>(), second> {};
struct hour : named_scaled_unit<hour, "h", mag<60>(), minute> {};
struct day : named_scaled_unit<day, "d", mag<24>(), hour> {};
}
Defining constants
------------------
[SIBrochure]_ states that:
The definition of the SI units is established in terms of a set of seven defining constants.
The complete system of units can be derived from the fixed values of these defining
constants, expressed in the units of the SI.
Those constants are provided in the *units/isq/si/constants.h* header file as::
namespace units::isq::si::si2019 {
template<Representation Rep = double>
inline constexpr auto hyperfine_structure_transition_frequency = frequency<hertz, Rep>(Rep{9'192'631'770});
template<Representation Rep = double>
inline constexpr auto speed_of_light = speed<metre_per_second, Rep>(299'792'458);
template<Representation Rep = double>
inline constexpr auto planck_constant = energy<joule, Rep>(6.62607015e-34) * time<second, Rep>(1);
template<Representation Rep = double>
inline constexpr auto elementary_charge = electric_charge<coulomb, Rep>(1.602176634e-19);
template<Representation Rep = double>
inline constexpr auto boltzmann_constant = energy<joule, Rep>(1.380649e-23) / thermodynamic_temperature<kelvin, Rep>(1);
template<Representation Rep = double>
inline constexpr auto avogadro_constant = Rep(6.02214076e23) / amount_of_substance<mole, Rep>(1);
template<Representation Rep = double>
inline constexpr auto luminous_efficacy = luminous_flux<lumen, Rep>(683) / power<watt, Rep>(1);
}
.. note::
Please note the nested `si2019` namespace. It is introduced in case those constants were changed/updated
by the :term:`SI` in the future.

View File

@ -1,17 +0,0 @@
Design Deep Dive
================
.. note::
For brevity all the code examples in this chapter assume::
using namespace units;
using namespace units::isq;
.. toctree::
:maxdepth: 2
design/directories
design/quantity
design/quantity_kind
design/downcasting

View File

@ -1,64 +0,0 @@
.. namespace:: units
Library Directories Structure
=============================
.. code-block:: text
units
├── bits
│ └── external
├── generic
└── isq
├── dimensions
├── iec80000
├── natural
└── si
├── cgs
├── fps
├── iau
├── imperial
├── international
├── typographic
└── us
- *./units*
- The main directory of the library.
- Contains headers files that define a public interface of the library framework.
- *./units/bits*
- Contains header files with implementation details for the library. Interface of
the tools provided here should not be standardized.
- *./units/bits/external*
- Contains header files of general purpose utilities that are not necessary
**mp-units** library specific. They are either implementation details of the
library or should be (or already are) the subject of separate standardization
proposals not related to a Physical Units library proposal.
- *./units/generic*
- Provides quantity types not related to any :term:`system of quantities`
(e.g. `dimensionless`, `angle`).
- *./units/isq*
- Contains the definition of quantity dimensions of International System of Quantities
(:term:`ISQ`).
- Its subfolders provide the definitions of various
:term:`systems of units <system of units>` with International System of Units (:term:`SI`)
being the most popular one.
.. seealso::
More information on provided :term:`systems of units <system of units>` can be
found in :ref:`reference/systems:Systems` chapter.
.. important::
While working with predefined systems please always include a header file with all
the definitions for the current system to limit the possibility of an ODR violation
(e.g. *units/isq/si/si.h*).

View File

@ -1,161 +0,0 @@
.. namespace:: units
The Downcasting Facility
========================
Problem statement
-----------------
Most of the C++ libraries in the world use template aliases to provide a friendly name for a
developer. Unfortunately, such aliases are quickly lost in a compilation process and as a
result the potential error log contains a huge source type rather than a short alias for it.
The same can be observed during debugging of a source code that use template aliases.
Let's assume that we want to provide a user friendly name for a derived dimension of capacitance
quantity. Other libraries will do it in the following way::
using dim_capacitance = detail::derived_dimension_base<exponent<si::dim_electric_current, 2>,
exponent<si::dim_length, -2>,
exponent<si::dim_mass, -1>,
exponent<si::dim_time, 4>>;
The above solution does provide a good developer's experience but a really poor one for the end
user. If we will get a compilation error message containing ``dim_capacitance`` in most cases
the compiler will print the following type instead of the alias::
units::detail::derived_dimension_base<units::exponent<units::isq::si::dim_electric_current, 2, 1>,
units::exponent<units::isq::si::dim_length, -2, 1>, units::exponent<units::isq::si::dim_mass,
-1, 1>, units::exponent<units::isq::si::dim_time, 4, 1> >
You can notice that in case of **mp-units** even this long syntax was carefully selected to
provide quite good user experience (some other units libraries produce a type that cannot easily
fit on one slide) but it is not questionable less readable than just ``dim_capacitance``.
.. note::
To better understand how the framework works and not clutter the text and graphs with
long types in the following examples we will switch from ``dim_capacitance`` to ``dim_area``.
The latter one has much shorter definition but the end result for both will be exactly the same -
user-friendly, short name printed by the compiler and the debugger.
As we lack opaque/strong typedefs in the C++ language the only way to improve our case is
to use inheritance:
.. image:: /_static/img/downcast_1.png
:align: center
..
http://www.nomnoml.com
[derived_dimension_base<exponent<si::dim_length, 2>>]<:-[dim_area]
This gives us a nice looking strong type when directly used by the user. However, we just got
ourselves into problems. The library's framework does not know how to switch from a long
instantiation of a ``derived_dimension_base`` class template that was generated as a result
of dimensional calculation to a nicely named child class assigned by the user for this
instantiation.
How it works?
-------------
To support this **mp-units** library introduces a new downcasting facility implemented fully
as a library feature. It creates 1-to-1 link between a long class template instantiation and a
strong type provided by the user. This provides automatic type substitution mechanism in the
framework.
.. important::
The above 1-1 correspondence means that only one child class can be provided for a specific
base class template instantiation. If a user will try to assign another child class to
already used base class template instantiation the program will not compile.
The downcasting facility is provided by injecting two classes into our hierarchy:
.. image:: /_static/img/downcast_2.png
:align: center
..
http://www.nomnoml.com
[downcast_base<detail::derived_dimension_base<exponent<si::dim_length, 2>>>]<:-[detail::derived_dimension_base<exponent<si::dim_length, 2>>]
[detail::derived_dimension_base<exponent<si::dim_length, 2>>]<:-[downcast_child<dim_area, detail::derived_dimension_base<exponent<si::dim_length, 2>>>]
[downcast_child<dim_area, detail::derived_dimension_base<exponent<si::dim_length, 2>>>]<:-[dim_area]
In the above example:
- ``dim_area`` is a downcasting target (child class)
- ``detail::derived_dimension_base`` class template instantiation is a downcasting source (base class)
- `downcast_base` is a class that implements :abbr:`CRTP (Curiously Recurring Template Pattern)`
idiom, stores the base of a downcasting operation in a ``downcast_base_type`` member type,
and provides only a Hidden Friend non-member function declaration of ``downcast_guide`` which is an
:abbr:`ADL (Argument Dependent Lookup)` entry point for the downcasting operation::
template<typename BaseType>
struct downcast_base {
using downcast_base_type = BaseType;
friend auto downcast_guide(downcast_base); // declaration only (no implementation)
};
.. important::
An important design point here is that this friend function does not return any specific type
in its declaration and no definition is provided at this point.
- `downcast_child` is another :abbr:`CRTP (Curiously Recurring Template Pattern)` class template
that defines the implementation of a non-member friend function of the `downcast_base` class
template::
template<typename Target, Downcastable T>
struct downcast_child : T {
friend auto downcast_guide(typename T::downcast_base) { return Target(); }
};
This is the place where the actual return type of the ``downcast_guide`` function is provided
which serves as a target type of the downcasting operation.
In the above class template definition `Downcastable` is a concepts that verifies if a type
implements and can be used in a downcasting facility::
template<typename T>
concept Downcastable =
requires {
typename T::downcast_base_type;
} &&
std::derived_from<T, downcast_base<typename T::downcast_base_type>>;
With such :abbr:`CRTP (Curiously Recurring Template Pattern)` types the only thing the user
has to do in order to register a new type in the downcasting facility is to publicly derive
from `downcast_child` and pass this type as the first template argument of the `downcast_child`
class template.
Until now we scoped on how we define the base and target of a downcasting operation. To
perform the actual downcasting operation a dedicated alias template is provided::
template<Downcastable T>
using downcast = decltype(detail::downcast_impl<T>());
`downcast` is used to obtain the target type of the downcasting operation registered for a
given instantiation in a base type. ``detail::downcast_impl`` checks if a downcasting
target is registered for the specific base class. If yes, it returns the registered type,
otherwise it works like a regular identity type trait returning a provided base class::
namespace detail {
template<typename T>
concept has_downcast_guide = requires(T t) { downcast_guide(t); };
template<typename T>
constexpr auto downcast_impl()
{
if constexpr(has_downcast_guide<T>)
return decltype(downcast_guide(std::declval<downcast_base<T>>()))();
else
return T();
}
}

View File

@ -1,62 +0,0 @@
.. namespace:: units
quantity
========
Interface
---------
The value of a quantity is generally expressed as the product of a number and a unit. The
unit is simply a particular example of the quantity concerned which is used as a reference,
and the number is the ratio of the value of the quantity to the unit.
`quantity` class template provides a similar interface to
`std::chrono::duration <https://en.cppreference.com/w/cpp/chrono/duration>`_.
The difference is that it uses ``double`` as a default representation and has
a few additional member types and functions::
template<Dimension D, UnitOf<D> U, Representation Rep = double>
class quantity {
public:
using dimension = D;
using unit = U;
using rep = Rep;
[[nodiscard]] static constexpr quantity one() noexcept;
// ...
};
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2>
requires detail::basic_arithmetic<Rep1, Rep2> && (!equivalent<D1, dim_invert<D2>>)
[[nodiscard]] constexpr Quantity auto operator*(const quantity<D1, U1, Rep1>& lhs,
const quantity<D2, U2, Rep2>& rhs);
template<Representation Value, typename D, typename U, typename Rep>
requires std::magma<std::ranges::divided_by, Value, Rep>
[[nodiscard]] constexpr Quantity auto operator/(const Value& v,
const quantity<D, U, Rep>& q);
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2>
requires detail::basic_arithmetic<Rep1, Rep2> && (!equivalent<D1, D2>)
[[nodiscard]] constexpr Quantity auto operator/(const quantity<D1, U1, Rep1>& lhs,
const quantity<D2, U2, Rep2>& rhs);
Additional functions provide the support for operations that result in a
different dimension type than those of their arguments. ``equivalent``
constraint requires two dimensions to be either the same or have convertible
units of base dimension (with the same reference unit).
Beside adding new elements a few other changes where applied compared to the
`std::chrono::duration <https://en.cppreference.com/w/cpp/chrono/duration>`_
class template:
1. The ``std::chrono::duration`` is using ``std::common_type_t<Rep1, Rep2>`` to find a common
representation for a calculation result. Such a design was reported as problematic
by SG6 (numerics study group) members as sometimes we want to provide a different
type in case of multiplication and different in case of division. ``std::common_type``
lacks that additional information. That is why `quantity` uses the resulting
type of a concrete operator operation.
2. ``quantity::operator%()`` is constrained with `treat_as_floating_point` type trait to limit the
types to integral representations only. Also ``quantity::operator%(Rep)`` takes ``Rep`` as a
template argument to limit implicit conversions.

View File

@ -1,52 +0,0 @@
.. namespace:: units
quantity_kind
=============
The ``quantity_kind`` class template provides a similar interface to ``quantity``.
Kinds
-----
The first template parameter of ``quantity_kind`` is a ``Kind``.
``Kind`` s, by themselves:
* Wrap a ``Dimension``, and
* opt into the downcasting facility.
If a dimensional analysis operator on a quantity of kind *A*
can result on a quantity of kind *B*,
*A* and *B* are *related*.
The library provides two ``Kind`` bases, ``kind`` and ``derived_kind``.
``kind`` is an entry point, and there's only one per set of related kinds.
``derived_kind`` is used to explicitly name other related kinds.
Unnamed, they look like ``detail::_kind_base<the-entry-kind, some_dimension>``.
Unnamed kinds, like unnamed units and dimensions,
allows (intermediate) results in formulas without having to name them.
Quantity kinds
--------------
``quantity_kind`` wraps a ``quantity`` and layers over its dimensional analysis.
While all properties of the ``quantity`` apply transparently,
results are always ``quantity_kind`` s related to the kind(s) of the argument(s).
One of the arguments to the dimensional analysis operators can also be ``Quantity``.
The way back to ``quantity`` is through the ``.common()`` observer.
Intra-kind operations
---------------------
``quantity_kind`` takes care of operators between related quantity kinds.
Intra-kind operations can be opted into as follows::
struct width : kind<width, dim_length> {};
struct height : kind<height, dim_length> {};
size2d operator+(QuantityKindOf<width> auto, QuantityKindOf<height> auto);

View File

@ -1,11 +0,0 @@
Examples
========
.. toctree::
:maxdepth: 2
examples/basics
examples/kalman_filter
examples/custom_representation
examples/custom_systems
examples/custom_utilities

View File

@ -1,18 +0,0 @@
Basics
======
The following examples highlight the basics of the library design.
.. toctree::
:maxdepth: 1
basics/hello_units
basics/clcpp_response
basics/avg_speed
basics/box_example
basics/capacitor_time_curve
basics/unknown_dimension
basics/foot_pound_second
basics/experimental_angle
basics/total_energy
basics/glide_computer

View File

@ -1,7 +0,0 @@
avg_speed
=========
.. literalinclude:: ../../../example/references/avg_speed.cpp
:caption: avg_speed.cpp
:start-at: #include
:linenos:

View File

@ -1,7 +0,0 @@
box_example
===========
.. literalinclude:: ../../../example/references/box_example.cpp
:caption: box_example.cpp
:start-at: #include
:linenos:

View File

@ -1,7 +0,0 @@
capacitor_time_curve
====================
.. literalinclude:: ../../../example/references/capacitor_time_curve.cpp
:caption: capacitor_time_curve.cpp
:start-at: #include
:linenos:

View File

@ -1,7 +0,0 @@
clcpp_response
==============
.. literalinclude:: ../../../example/references/clcpp_response.cpp
:caption: clcpp_response.cpp
:start-at: #include
:linenos:

View File

@ -1,7 +0,0 @@
experimental_angle
==================
.. literalinclude:: ../../../example/references/experimental_angle.cpp
:caption: experimental_angle.cpp
:start-at: #include
:linenos:

View File

@ -1,7 +0,0 @@
foot_pound_second
=================
.. literalinclude:: ../../../example/references/foot_pound_second.cpp
:caption: foot_pound_second.cpp
:start-at: #include
:linenos:

View File

@ -1,81 +0,0 @@
.. namespace:: units
glide_computer
==============
This example presents the usage of:
- `quantity_point` to mark "absolute" quantities like ``timestamp``
- `quantity_point_kind` to mark "absolute" kinds of quantities like ``altitude`` (as opposed to ``height``),
- different kinds for length, time, and speed,
- the use of quantity kinds to show how to handle 3D space for aviation needs,
- unit constants to initialize the database
- quantities text output formatting,
- cooperation with `std::chrono`.
.. literalinclude:: ../../../example/glide_computer/include/glide_computer.h
:caption: glide_computer.h
:start-at: #include
:end-at: // - flight path exactly on a shortest possible line to destination
:linenos:
:lineno-match:
The use of `quantity_kind` and `quantity_point_kind` provides strong typing
that divide quantities and quantity points to the ones on a horizontal (X, Y) plane and vertical (Z) axis.
Their purpose is to make different kinds of quantity
(i.e. length) separate strong types (i.e. distance, height).
Additionally, separating a quantity from its quantity point
means that we can define a ``height`` and ``altitude`` as different strong types.
A quantity point provides a more restricted interface meant for absolute calculations.
The glide calculator engine also take benefits from different :term:`kinds of quantities <kind>`.
For example we have 3 for a quantity of length:
- ``distance`` - a relative horizontal distance between 2 points on Earth
- ``height`` - a relative altitude difference between 2 points in the air
- ``altitude`` - an absolute altitude value measured form the mean sea level (AMSL).
.. literalinclude:: ../../../example/glide_computer/include/glide_computer.h
:caption: glide_computer.h
:start-after: // - flight path exactly on a shortest possible line to destination
:end-before: // text output
:linenos:
:lineno-match:
Next a custom text output is provided both for C++ output streams and the text formatting facility.
.. literalinclude:: ../../../example/glide_computer/include/glide_computer.h
:caption: glide_computer.h
:start-at: // text output
:end-before: // definition of glide computer databases and utilities
:linenos:
:lineno-match:
The engine of this simple glide computer works on quantities of the SI units with a floating-point
representation. The user can pass any unit valid for a given quantity and the library will automatically
convert it to the one required by the engine interface.
The glide calculator takes task created as a list of waypoints, glider performance data, weather conditions,
safety constraints, and a towing height.
.. literalinclude:: ../../../example/glide_computer/include/glide_computer.h
:caption: glide_computer.h
:start-at: // definition of glide computer databases and utilities
:linenos:
:lineno-match:
.. literalinclude:: ../../../example/references/glide_computer_example.cpp
:caption: glide_computer_example.cpp
:start-at: #include
:linenos:
:lineno-match:
Having all of that it estimates the number of flight phases (towing, circling, gliding, final glide)
needed to finish a task. As an output it provides the duration needed to finish the task while
flying a selected glider in the specific weather conditions.
.. literalinclude:: ../../../example/glide_computer/glide_computer.cpp
:caption: glide_computer.cpp
:start-at: #include
:linenos:
:lineno-match:

View File

@ -1,7 +0,0 @@
hello_units
===========
.. literalinclude:: ../../../example/hello_units.cpp
:caption: hello_units.cpp
:start-at: #include
:linenos:

View File

@ -1,7 +0,0 @@
total_energy
============
.. literalinclude:: ../../../example/references/total_energy.cpp
:caption: total_energy.cpp
:start-at: #include
:linenos:

View File

@ -1,7 +0,0 @@
unknown_dimension
=================
.. literalinclude:: ../../../example/references/unknown_dimension.cpp
:caption: unknown_dimension.cpp
:start-at: #include
:linenos:

View File

@ -1,10 +0,0 @@
Custom Representation Types
===========================
The following examples show how to work with custom represenation types.
.. toctree::
:maxdepth: 1
custom_representation/measurement
custom_representation/linear_algebra

View File

@ -1,7 +0,0 @@
linear_algebra
==============
.. literalinclude:: ../../../example/references/linear_algebra.cpp
:caption: linear_algebra.cpp
:start-at: #include
:linenos:

View File

@ -1,7 +0,0 @@
measurement
===========
.. literalinclude:: ../../../example/measurement.cpp
:caption: measurement.cpp
:start-at: #include
:linenos:

View File

@ -1,9 +0,0 @@
Custom Systems
==============
The following examples show how to define custom systems of units and quantities.
.. toctree::
:maxdepth: 1
custom_systems/custom_systems

View File

@ -1,7 +0,0 @@
custom_systems
==============
.. literalinclude:: ../../../example/custom_systems.cpp
:caption: custom_systems.cpp
:start-at: #include
:linenos:

View File

@ -1,9 +0,0 @@
Custom Utilites
===============
The following examples present how to reuse library facilities to create custom utilities.
.. toctree::
:maxdepth: 1
custom_utilities/conversion_factor

View File

@ -1,7 +0,0 @@
conversion_factor
=================
.. literalinclude:: ../../../example/conversion_factor.cpp
:caption: conversion_factor.cpp
:start-at: #include
:linenos:

View File

@ -1,17 +0,0 @@
Kalman Filter Tutorial
======================
The following examples are based on the `Kalman Filter <https://www.kalmanfilter.net>`_ tutorial.
.. toctree::
:maxdepth: 1
kalman_filter/kalman
kalman_filter/example_1
kalman_filter/example_2
kalman_filter/example_3
kalman_filter/example_4
kalman_filter/example_5
kalman_filter/example_6
kalman_filter/example_7
kalman_filter/example_8

View File

@ -1,9 +0,0 @@
Example 1 - Weighting the gold
==============================
Implementation of: https://www.kalmanfilter.net/alphabeta.html#ex1
.. literalinclude:: ../../../example/kalman_filter/kalman_filter-example_1.cpp
:caption: kalman_filter-example_1.cpp
:start-at: #include
:linenos:

View File

@ -1,9 +0,0 @@
Example 2 - Tracking the constant velocity aircraft in one dimension
====================================================================
Implementation of: https://www.kalmanfilter.net/alphabeta.html#ex2
.. literalinclude:: ../../../example/kalman_filter/kalman_filter-example_2.cpp
:caption: kalman_filter-example_2.cpp
:start-at: #include
:linenos:

View File

@ -1,9 +0,0 @@
Example 3 - Tracking accelerating aircraft in one dimension
===========================================================
Implementation of: https://www.kalmanfilter.net/alphabeta.html#ex3
.. literalinclude:: ../../../example/kalman_filter/kalman_filter-example_3.cpp
:caption: kalman_filter-example_3.cpp
:start-at: #include
:linenos:

View File

@ -1,9 +0,0 @@
Example 4 - Tracking accelerating aircraft with the α−β−γ filter
================================================================
Implementation of: https://www.kalmanfilter.net/alphabeta.html#ex4
.. literalinclude:: ../../../example/kalman_filter/kalman_filter-example_4.cpp
:caption: kalman_filter-example_4.cpp
:start-at: #include
:linenos:

View File

@ -1,9 +0,0 @@
Example 5 - Estimating the building height
==========================================
Implementation of: https://www.kalmanfilter.net/kalman1d.html#ex5
.. literalinclude:: ../../../example/kalman_filter/kalman_filter-example_5.cpp
:caption: kalman_filter-example_5.cpp
:start-at: #include
:linenos:

View File

@ -1,9 +0,0 @@
Example 6 - Estimating the temperature of the liquid in a tank
==============================================================
Implementation of: https://www.kalmanfilter.net/kalman1d.html#ex6
.. literalinclude:: ../../../example/kalman_filter/kalman_filter-example_6.cpp
:caption: kalman_filter-example_6.cpp
:start-at: #include
:linenos:

View File

@ -1,9 +0,0 @@
Example 7 - Estimating the temperature of the heating liquid I
==============================================================
Implementation of: https://www.kalmanfilter.net/kalman1d.html#ex7
.. literalinclude:: ../../../example/kalman_filter/kalman_filter-example_7.cpp
:caption: kalman_filter-example_7.cpp
:start-at: #include
:linenos:

View File

@ -1,9 +0,0 @@
Example 8 - Estimating the temperature of the heating liquid II
===============================================================
Implementation of: https://www.kalmanfilter.net/kalman1d.html#ex8
.. literalinclude:: ../../../example/kalman_filter/kalman_filter-example_8.cpp
:caption: kalman_filter-example_8.cpp
:start-at: #include
:linenos:

View File

@ -1,7 +0,0 @@
Common utility header file (``kalman.h``)
=========================================
.. literalinclude:: ../../../example/kalman_filter/kalman.h
:caption: kalman.h
:start-at: #include
:linenos:

View File

@ -1,131 +0,0 @@
.. namespace:: units
FAQ
===
.. contents:: Questions:
:local:
General
-------
Why dimensions depend on units and not vice versa?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Most of the libraries define units in terms of dimensions and this was also an
initial approach for this library. However, it turns out that for such a design
it is hard to provide support for all the required scenarios.
The first of them is to support multiple unit systems (like SI, CGS, ...) where
each of can have a different base unit for the same dimension. Base quantity of
dimension length in SI should use ``m`` to print the unit symbol to the text
output, while the same dimension for CGS should use ``cm``. Also, it helps in
conversions among those systems.
The second one is to support natural units where more than one dimension can be
measured with the same unit (i.e. ``GeV``). Also if someone will decide to
implement a systems where SI quantities of the same kind are expressed as
different dimensions (i.e. height, width, and depth) all of them will just be
measured in meters.
Why other systems are defined in the `isq::si` namespace?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
All systems defined in the `isq::si` namespace are defined in terms of
base units that are convertible to the :term:`SI` units. This enables conversions
of units of the same physical dimension between different systems.
.. seealso::
More details on this subject can be found in the
:ref:`use_cases/extensions:Custom Systems` chapter.
Why a dimensionless quantity is not just an fundamental arithmetic type?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In the initial design of this library the resulting type of the division of
two quantities was their common representation type::
static_assert(std::is_same_v<decltype(10 * km / (5 * km)), std::int64_t>);
The reasoning behind it was to not provide a false impression of a strong `quantity` type
for something that looks and feels like a regular number. Also all of the mathematic
and trigonometric functions were working fine out of the box with such representation
types, so we did not have to rewrite ``sin()``, ``cos()``, ``exp()``, and others.
However, the feedback we got from the production usage was that such an approach
is really bad for generic programming. It is really hard to handle the result of
division (or multiplication) of two quantities as it might be either a `quantity`
or a fundamental type. If we want to raise such a result to some power we have to
either use ``units::pow`` or ``std::pow`` depending on the resulting type. Those
are only a few from many similar issues related to such an approach.
This is why it was decided to go with the current approach.
.. seealso::
More information on the current design can be found in
the :ref:`framework/quantities:Dimensionless Quantities` chapter.
Why do we spell ``metre`` instead of ``meter``?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Well, this is how [ISO80000]_ defines it (British English spelling by default).
User Defined Literals (UDLs)
----------------------------
Why all UDLs are prefixed with ``_q_`` instead of just using unit symbol?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. note::
Every ``_q_*`` UDL will be replaced by the ``q_*`` literal when/if **mp-units**
will become a part of the C++ Standard Library.
Usage of only unit symbols in UDLs would be a preferred approach (less to type,
easier to understand and maintain). However, while increasing the coverage for
the library we learned that there are a lot unit symbols that conflict with
built-in types or numeric extensions. A few of those are: ``F`` (farad),
``J`` (joule), ``W`` (watt), ``K`` (kelvin), ``d`` (day),
``l`` or ``L`` (litre), ``erg``, ``ergps``. For a while for those we used ``_``
prefix to make the library work at all, but at some point we had to unify the
naming and we came up with ``_q_`` prefix which results in a creation of
quantity of a provided unit.
Text formatting
---------------
Why Unicode quantity symbols are used by default instead of ASCII-only characters?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Both C++ and :term:`SI` ([ISO80000]_) are standardized by the
:abbr:`ISO (International Organization for Standardization)`. :term:`SI` standard
specifies Unicode symbols as the official unit names for some quantities (i.e. ``Ω``
symbol for the resistance quantity). As **mp-units** library
is being proposed for standardization as a part of the C++ Standard Library we have
to obey the rules and be consistent with ISO specifications.
.. seealso::
We do understand engineering reality and constraints and that is why the library
has the option of :ref:`framework/text_output:ASCII-only quantity symbols`.
Compilation Errors
------------------
error: reference to time is ambiguous
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Unfortunately, if `using-directives <https://en.cppreference.com/w/cpp/language/namespace#Using-directives>`_
(i.e. ``using namespace units::isq::si``) are being used, `units::isq::si::time`
will collide with C `time <https://en.cppreference.com/w/c/chrono/time>`_ function. In
such a case the library's ``time`` function needs to be prefixed with at least one (or all)
namespace names.

View File

@ -1,25 +0,0 @@
Framework Basics
================
.. note::
For brevity all the code examples in this chapter assume::
using namespace units;
using namespace units::isq;
.. toctree::
:maxdepth: 2
framework/basic_concepts
framework/quantity_like
framework/quantities
framework/quantity_points
framework/quantity_kinds
framework/dimensions
framework/magnitudes
framework/units
framework/arithmetics
framework/constants
framework/conversions_and_casting
framework/text_output

View File

@ -1,148 +0,0 @@
.. namespace:: units
Arithmetics
===========
Quantities
----------
Quantities of the same dimension can be easily added or subtracted with
each other and the result will always be a quantity of the same dimension:
.. code-block::
:emphasize-lines: 3-4
Length auto dist1 = 2 * m;
Length auto dist2 = 1 * m;
Length auto res1 = dist1 + dist2;
Length auto res2 = dist1 - dist2;
Additionally, we can always multiply or divide a quantity by a
:term:`scalable number` and in such a case the quantity's dimension will also
not change:
.. code-block::
:emphasize-lines: 2-4
Length auto dist = 2 * m;
Length auto res1 = dist * 2; // 4 m
Length auto res2 = 3 * res1; // 12 m
Length auto res3 = res2 / 2; // 6 m
However, if we try to multiply or divide quantities of the same or
different dimensions, or we will divide a scalable number by a quantity, we most
probably will always end up in a quantity of a yet another dimension:
.. code-block::
:emphasize-lines: 4-6
Length auto dist1 = 2 * m;
Length auto dist2 = 3 * m;
Time auto dur1 = 2 * s;
Area auto res1 = dist1 * dist2; // 6 m²
Speed auto res2 = dist1 / dur1; // 1 m/s
Frequency auto res3 = 10 / dur1; // 5 Hz
However, please note that there is an exception from the above rule.
In case we divide the same dimensions, or multiply by the inverted
dimension, than we will end up with just a dimensionless quantity:
.. code-block::
:emphasize-lines: 4-5
Time auto dur1 = 10 * s;
Time auto dur2 = 2 * s;
Frequency auto fr1 = 5 * Hz;
Dimensionless auto v1 = dur1 / dur2; // quantity(5)
Dimensionless auto v2 = dur1 * fr1; // quantity(50)
Quantity Kinds
--------------
Quantity kinds behave the same as quantities for all operations,
except that the quantity types in the operators' declarations
are quantity kind types instead.
Additionally, for the dimensional analysis operators,
you can use a quantity argument instead of a quantity kind.
.. code-block::
:emphasize-lines: 8-9
struct height_kind : kind<height_kind, dim_length> {};
struct rate_of_climb_kind : derived_kind<rate_of_climb_kind, dim_speed, height_kind> {};
template <Unit U, Representation Rep = double> using height = quantity_kind<height_kind, U, Rep>;
template <Unit U, Representation Rep = double> using rate_of_climb = quantity_kind<rate_of_climb_kind, U, Rep>;
height h{100 * m};
rate_of_climb rate = h / (25 * s);
// quantity_kind<rate_of_climb_kind, si::metre_per_second, int>(4 * m / s)
.. code-block::
:emphasize-lines: 8-12
struct width_kind : kind<width_kind, dim_length> {};
struct horizontal_area_kind : derived_kind<horizontal_area_kind, dim_area, width_kind> {};
template <Unit U, Representation Rep = double> using width = quantity_kind<width_kind, U, Rep>;
template <Unit U, Representation Rep = double> using horizontal_area = quantity_kind<horizontal_area_kind, U, Rep>;
width w{5 * m};
horizontal_area area1 = w * w;
// quantity_kind<horizontal_area_kind, si::metre_per_second, int>(25 * m * m)
width w2 = area1 / w; // quantity_kind<width_kind, si::metre, int>(5 * m)
auto q1 = w / w; // Dimensionless quantity kinds related to width
auto q2 = w / (5 * m); // with .common() equal to quantity{1}
Quantity Points
---------------
Quantity points have a more restricted set of operations.
Quantity can be added to or subtracted
from a quantity point of the same origin.
The result will always be a quantity point of the same origin:
.. code-block::
:emphasize-lines: 3-5
Length auto dist1 = 2 * m;
Length auto dist2 = 1 * m;
QuantityPoint auto res1 = quantity_point{dist1} + dist2;
QuantityPoint auto res2 = dist1 + quantity_point{dist2};
QuantityPoint auto res3 = quantity_point{dist1} - dist2;
We can also subtract two quantity points.
The result is a relative quantity of the same dimension:
.. code-block::
:emphasize-lines: 3
Length auto dist1 = 2 * m;
Length auto dist2 = 1 * m;
Length auto res1 = quantity_point{dist1} - quantity_point{dist2};
.. note::
It is not allowed to:
- add quantity points,
- subtract a quantity point from a quantity,
- multiply nor divide quantity points with anything else, and
- mix quantity points with different origins:
.. code-block::
:emphasize-lines: 3-5
Length auto dist1 = 2 * m;
Length auto dist2 = 1 * m;
auto res1 = quantity_point{dist1} + quantity_point{dist2}; // ERROR
auto res2 = dist1 - quantity_point{dist2}; // ERROR
auto res3 = quantity_point{dist1} / (2 * s); // ERROR
auto res4 = quantity_point{std::chrono::utc_second{1s}} +
quantity_point{std::chrono::sys_second{1s}}; // ERROR
Quantity Point Kinds
--------------------
The same restrictions of a quantity point with respect to its quantity
apply to a quantity point kind with respect to its quantity kind.

View File

@ -1,117 +0,0 @@
.. namespace:: units
Basic Concepts
==============
The most important concepts in the library are `Unit`, `Dimension`,
`Quantity`, `QuantityPoint`, `QuantityKind`, and `QuantityPointKind`:
.. raw:: html
<object data="../_images/concepts.svg" type="image/svg+xml" class="align-center" style="max-width: 100%;"></object>
..
https://www.planttext.com
@startuml
skinparam monochrome true
skinparam shadowing false
skinparam backgroundColor #fcfcfc
hide circle
hide members
show class methods
package Unit <<Frame>> [[../../framework/units.html]] {
}
package Dimension <<Frame>> [[../../framework/dimensions.html]] {
}
package Kind <<Frame>> [[../../framework/quantity_kinds.html#kind-creation]] {
abstract kind<Dimension> [[../../framework/quantity_kinds.html#kind-creation]]
}
package PointKind <<Frame>> [[../../framework/quantity_kinds.html#quantity-point-kinds]] {
abstract point_kind<Kind, PointOrigin> [[../../framework/quantity_kinds.html#quantity-point-kinds]]
}
package PointOrigin <<Frame>> [[../../framework/quantity_points.html#point-origins]] {
abstract point_origin<Dimension> [[../../framework/quantity_points.html#point-origins]]
}
package Quantity <<Frame>> [[../../framework/quantities.html]] {
class quantity<Dimension, Unit, Rep> [[../../framework/quantities.html#construction]] {
rep number()
}
}
package QuantityPoint <<Frame>> [[../../framework/quantity_points.html]] {
class quantity_point<PointOrigin, Unit, Rep> [[../../framework/quantity_points.html#construction]] {
quantity relative()
}
}
package QuantityKind <<Frame>> [[../../framework/quantity_kinds.html]] {
class quantity_kind<Kind, Unit, Rep> [[../../framework/quantity_kinds.html#construction]] {
quantity common()
}
}
package QuantityPointKind <<Frame>> [[../../framework/quantity_kinds.html#quantity-point-kinds]] {
class quantity_point_kind<PointKind, Unit, Rep> [[../../framework/quantity_kinds.html#quantity-point-kinds]] {
quantity_kind relative()
}
}
Unit <.. Dimension
Dimension <... Quantity
Unit <... Quantity
Dimension <... Kind
Dimension <... PointOrigin
PointOrigin <... PointKind
Kind <... PointKind
Unit <... QuantityPoint
PointOrigin <... QuantityPoint
quantity --* quantity_point
Unit <... QuantityKind
Kind <... QuantityKind
quantity --* quantity_kind
Unit <... QuantityPointKind
PointKind <... QuantityPointKind
quantity_kind --* quantity_point_kind
@enduml
`Unit` is a basic building block of the library. Every dimension works with
a concrete hierarchy of units. Such hierarchy defines a reference unit and
often a few scaled versions of it. Examples: ``second``, ``metre``, ``kilometre_per_hour``.
`Dimension` concept matches a dimension of either a base or derived quantity.
`base_dimension` is instantiated with a unique symbol identifier and a base
unit. `derived_dimension` is a list of exponents of either base or other
derived dimensions. Examples: ``si::dim_time``, ``si::dim_length``, ``si::dim_speed``.
`Quantity` is a concrete amount of a unit for a specified dimension with a
specific representation. Examples: ``quantity<si::dim_time, si::second, int>``,
``si::length<si::metre, int>``, ``si::speed<si::kilometre_per_hour>``.
`QuantityPoint` is an absolute `Quantity` with respect to an origin.
Examples: timestamp (as opposed to duration), absolute temperature
(as opposed to temperature difference).
`QuantityKind` is a `Quantity` with more specific usage. Examples:
distance (``horizonal_kind``) and height (``vertical_kind``) are different kinds
of a length quantity.
`QuantityPointKind` is an absolute `QuantityKind` with respect to an origin.
Examples: altitude is a quantity point of ``vertical_kind`` (as opposed to
height).

View File

@ -1,33 +0,0 @@
.. namespace:: units
Quantity Constants
==================
In the **mp-units** library quantity constants are implemented as variable
templates of `quantity` types parametrized by the quantity's representation
type.
Additionally, in case of the :term:`SI` its physical constants are put in
separate namespaces named after the official release of the :term:`SI`
specification. This is needed to be able to provide backward and forward
compatibility as exact values of physical constants tend to change with time
(in most cases they are getting more and more accurate with every
specification release).
For example the speed of light constant in :term:`SI` is defined as::
namespace si::si2019 {
template<Representation Rep = double>
inline constexpr auto speed_of_light = speed<metre_per_second, Rep>(299792458);
}
The same constant defined for natural units may be provided as::
namespace natural {
template<Representation Rep = double>
inline constexpr auto speed_of_light = speed<one, Rep>(1);
}

View File

@ -1,190 +0,0 @@
.. namespace:: units
Conversions and Casting
=======================
Programmers who are not full-time programming language geeks **hate lack of
implicit conversions** that they consider reasonable. Violate their expectations
for reasons they consider hypothetical problems and you get disuse. In type
terms, I usually **translate "reasonable" to "not narrowing" aka "not loosing
information."** That can reasonably easily be explained to non-language-experts.
-- *Bjarne Stroustrup*
The library tries to follow the above principle and at the same time is also consistent
with conversions of ``std::chrono::duration``.
No Conversions
--------------
No conversions (either implicit or explicit) are available across quantities of
different dimensions::
si::length<si::metre> d1 = 1 * s; // Compile-time error
si::length<si::metre> d2(1 * s); // Compile-time error
auto d3 = quantity_cast<si::metre>(1 * s); // Compile-time error
Implicit
--------
Implicit conversions are allowed only across quantities of the same dimension:
- for integral types with ratios that guarantee no precision loss::
si::length<si::metre, int> d1 = 1 * km + 1 * m; // OK
si::length<si::millimetre, int> d2 = 1 * km + 1 * m; // OK
si::length<si::kilometre, int> d3 = 1 * km + 1 * m; // Compile-time error
si::length<si::kilometre, int> d4(1 * km + 1 * m); // Compile-time error
si::length<si::metre, int> d5 = 1 * m + 1 * ft; // Compile-time error
si::length<si::metre, int> d6(1 * m + 1 * ft); // Compile-time error
- from an integral to a floating-point representation even in case of a truncating
ratio::
si::length<si::kilometre, double> d7 = 1 * km + 1 * m; // OK
si::length<si::metre, double> d8 = 1 * m + 1 * ft; // OK
- when both sides use a floating-point representation::
si::length<si::metre, int> d9 = 1.23 * m; // Compile-time error
si::length<si::metre, double> d10 = 1.23 * m; // OK
Explicit
--------
Explicit conversions are available with the `quantity_cast`, `quantity_point_cast`,
`quantity_kind_cast`, and `quantity_point_kind_cast` function templates.
They are especially useful to force a truncating conversion across quantities of the same
dimension for integral representation types and ratios that may cause precision loss::
si::length<si::kilometre, int> d1 = quantity_cast<kilometre>(1 * km + 1 * m); // OK
si::length<si::kilometre, int> d2 = quantity_cast<kilometre>(1 * s); // Error
.. seealso::
Explicit casts are also really useful when working with legacy interfaces.
More information on this subject can be found in the
:ref:`use_cases/legacy_interfaces:Working with Legacy Interfaces` chapter.
Quantity Cast Overloads
^^^^^^^^^^^^^^^^^^^^^^^
`quantity_cast` comes with several overloads:
.. code-block::
:linenos:
std::cout << "Distance: " << quantity_cast<si::length<si::metre, int>>(d) << '\n';
std::cout << "Distance: " << quantity_cast<si::dim_length>(d) << '\n';
std::cout << "Distance: " << quantity_cast<si::metre>(d) << '\n';
std::cout << "Distance: " << quantity_cast<int>(d) << '\n';
std::cout << "Distance: " << quantity_cast<si::dim_length, si::metre>(d) << '\n';
`quantity_cast` in line #1 takes a specific target `quantity` type to which an explicit
cast should be performed. This option will change multiple quantity properties at once
(unit, representation, etc). However, it is also possible to force only some properties at
once and leave the rest intact:
- line #2 forces only a specific destination dimension type,
- line #3 forces only a specific destination unit type,
- line #4 sets only a representation type to the type provided by the user,
- line #5 forces both a specific dimension and a unit while preserving the original
representation type.
`quantity_point_cast` takes anything that works for `quantity_point`
or a specific target `quantity_point`::
std::cout << "Point: " << quantity_point_cast<decltype(quantity_point{0 * m})>(d) << '\n';
For a single explicit template argument, `quantity_point_kind_cast` is a superset of
`quantity_kind_cast`, which is also a superset of `quantity_cast`.
For the (dimension, unit) pair of explicit arguments case of `quantity_cast`,
`quantity_point_kind_cast` and `quantity_kind_cast` accept a `PointKind` and `Kind`
instead of a `Dimension`, respectively.
.. seealso::
For more information on conversion and casting and on how to extend the above
"integral" vs "floating-point" logic please refer to the
:ref:`use_cases/custom_representation_types:Using Custom Representation Types` chapter.
Implicit conversions of dimensionless quantities
------------------------------------------------
As noted in the :ref:`framework/quantities:Dimensionless Quantities` chapter,
:term:`quantity of dimension one` is somehow special but still obey most of the rules defined
for quantities. However, as they represent numbers it would be highly uncomfortable to every
time type::
const auto d1 = 10 * km;
const auto d2 = 3 * km;
if(d1 / d2 > dimensionless<one>(2)) {
// ...
}
or::
const auto fill_time_left = (box.height / box.fill_level(measured_mass) -
dimensionless<one>(1)) * fill_time;
This is why it was decided to allow the ``dimensionless<one>`` quantity of any
representation type to be implicitly constructible from this representation type.
With that the above examples can be rewritten as follows::
const auto d1 = 10 * km;
const auto d2 = 3 * km;
if(d1 / d2 > 2) {
// ...
}
and::
const auto fill_time_left = (box.height / box.fill_level(measured_mass) - 1) * fill_time;
The above is true only for dimensionless quantities of `one` unit. If our quantity have a unit with
ratio different than ``1`` the implicit conversion will not happen. This is to prevent cases were the code
could be ambiguous. For example::
Dimensionless auto foo(Length auto d1, Length auto d2)
{
return d1 / d2 + 1;
}
As long as we can reason about what such code means for ``foo(10 * km, 2 * km)`` it is not that obvious
at all in the case of ``foo(10 * cm, 2 * ft)``. To make such code to compile for every case we have to
either change the type of the resulting unit to the one having ``ratio(1)`` (:term:`coherent derived unit`)::
Dimensionless auto foo(Length auto d1, Length auto d2)
{
return quantity_cast<one>(d1 / d2) + 1;
}
or to explicitly state what is the unit of our dimensionless value, e.g. `one`, `percent`, etc::
Dimensionless auto foo(Length auto d1, Length auto d2)
{
return d1 / d2 + dimensionless<one>(1);
}
There is one more important point to note here. As the the dimensionless quantity is more than just
a number, it is never implicitly converted back to the representation type. This means that the following
code will not compile::
auto v = std::exp(10 * m / (5 * m));
To make it compile fine we have to either explicitly get the value stored in the quantity::
auto v = std::exp(quantity_cast<one>(10 * m / (5 * m)).number());
or use a mathematical wrapper function from `units` namespace::
auto v = units::exp(10 * m / (5 * m));
.. important::
Always remember to explicitly cast the quantity to the destination unit with `quantity_cast` before
calling `quantity::number()`!

View File

@ -1,206 +0,0 @@
.. namespace:: units
Dimensions
==========
In the previous chapter we briefly introduced the notion of a physical
:term:`dimension`. Now it is time to learn much more about this subject.
Length, time, speed, area, energy are only a few examples of physical
dimensions.
.. raw:: html
<object data="../_images/dimensions.svg" type="image/svg+xml" class="align-center" style="max-width: 100%;"></object>
..
https://www.planttext.com
Base Dimensions
---------------
The quantities of base dimensions are called
:term:`base quantities <base quantity>` which are the atomic building blocks
of a :term:`system of quantities`. For example the The International System
of Units (:term:`SI`) defines 7 of them: length, mass, time, electric
current, thermodynamic temperature, substance, and luminous intensity.
To define a new base dimension the `base_dimension` class template is
provided. For example the SI base dimension of length can be defined as::
namespace si {
struct dim_length : base_dimension<"L", metre> {};
}
In the above code sample ``"L"`` is an base dimension's unique identifier
and `isq::si::metre` is a :term:`base unit` of this base dimension. We can
obtain those back easily with::
static_assert(si::dim_length::symbol == "L");
static_assert(is_same_v<si::dim_length::base_unit, si::metre>);
Derived Dimensions
------------------
The quantities of derived dimensions are called
:term:`derived quantities <derived quantity>` and are derived from base
quantities. This means that they are created by multiplying or dividing
quantities of other dimensions.
The [SIBrochure]_ states:
All other quantities, with the exception of counts, are derived quantities, which may be
written in terms of base quantities according to the equations of physics. The dimensions of
the derived quantities are written as products of powers of the dimensions of the base
quantities using the equations that relate the derived quantities to the base quantities.
In general the dimension of any quantity :math:`Q` is written in the form of a dimensional product,
:math:`dim Q = T^\alpha L^\beta M^\gamma I^\delta \Theta^\varepsilon N^\zeta J^\eta`
where the exponents :math:`\alpha`, :math:`\beta`, :math:`\gamma`, :math:`\delta`, :math:`\varepsilon`,
:math:`\zeta` and :math:`\eta`, which are generally small integers, which can be positive,
negative, or zero, are called the dimensional exponents.
Looking at the previous code snippets the area, speed, or frequency are
the examples of such quantities. Each derived quantity can be represented
as a unique list of exponents of base quantities. For example:
- an area is a length base quantity raised to the exponent ``2``
- a speed is formed from the length base quantity with exponent ``1``
and time base quantity with exponent ``-1``.
The above dimensions can be defined in the library with the
`derived_dimension` class template as follows::
namespace si {
struct dim_area : derived_dimension<dim_area, square_metre,
exponent<dim_length, 2>> {};
struct dim_speed : derived_dimension<dim_speed, metre_per_second,
exponent<dim_length, 1>, exponent<dim_time, -1>> {};
}
In the above code sample `isq::si::square_metre` and
`isq::si::metre_per_second` are the
:term:`coherent derived units <coherent derived unit>` of those derived dimensions.
Coherent unit argument is followed by the list of exponents that form this
derived dimension. This list is called a :term:`recipe` of this derived
dimension and may contain both base and derived dimensions. In the latter
case the dimension is being extracted to base dimensions by the framework
itself. The order and types of dimensions used in the recipe determine how
an dimension's unnamed unit symbol is being printed in the text output.
.. seealso::
More information on how the :term:`recipe` affect the printed symbol
of unnamed unit can be found in the :ref:`framework/units:Derived Unnamed Units`
chapter.
It is important to mention here that beside text output the order and
the number of elements in the `derived_dimension` definition does not
matter. Even if we define the above as:
.. code-block::
:emphasize-lines: 4, 6
namespace si {
struct dim_area : derived_dimension<dim_area, square_metre,
exponent<dim_length, 1>, exponent<dim_length, 1>> {};
struct dim_speed : derived_dimension<dim_speed, metre_per_second,
exponent<dim_time, -1>, exponent<dim_length, 1>> {};
}
the library will do its magic and will end up with the same
:term:`normalized derived dimension` which will allow the dimensional
analysis in the library to work as expected.
.. note::
The first template argument of `derived_dimension` is the type of the
child class inherited from the instantiation of this `derived_dimension`
class template. This is called a
:abbr:`CRTP (Curiously Recurring Template Parameter)` Idiom and is used
in many places in this library to provide
:ref:`design/downcasting:The Downcasting Facility`.
Obtaining a Unit of the Dimension
---------------------------------
In order to obtain the base/coherent unit of any dimension type a
`dimension_unit` helper was introduced::
static_assert(is_same_v<dimension_unit<si::dim_length>, si::metre>);
static_assert(is_same_v<dimension_unit<si::dim_speed>, si::metre_per_second>);
How do you feel about:
inline constexpr second second;
?
We could do the same to dimensions to not have to type dim_length{} all the time.
6 replies 2 new
@JohelEGP
JohelEGP
2 days ago
mp_units::units::second is a variable. The reference isq::si::second could stay a type and s continue to be a variable.
@mpusz
mpusz
2 days ago
Maintainer
Author
The problem is the following:
Variables are really needed for a new design. We can ask users to put {} after every dimension unit, and reference types but it would be really nasty and a lot of boilerplate.
Short names have to be opt-in as they collide with a lot of code (especially on MSVC).
@JohelEGP
JohelEGP
yesterday
As pointed out by #389 (reply in thread), I think it'd be OK suffix _t to the types.
@mpusz
mpusz
10 hours ago
Maintainer
Author
It will be visible in the compilation errors, which is inconvenient :-(
Instead of:
quantity<reference<derived_dimension<length_dim, per<time_dim>>, derived_unit<metre, per<second>>>
we will have something like:
quantity<reference<derived_dimension<length_dim_t, per<time_dim_t>>, derived_unit<metre_t, per<second_t>>>
Personally, I like the first output more.
Note that definition like:
inline constexpr second second;
besides, being really unconventional, is allowed by the language and will not impact our users at all. A user is about to always work with values in the code and observe types in the compilation errors. Using the same nicely blends those two domains together.
@mpusz
mpusz
10 hours ago
Maintainer
Author
I could use a list of values instead of types as template parameters in the dervied_dimension and derived_unit but in such case the error would look like:
quantity<reference<derived_dimension<length_dim{}, per<time_dim{}>{}>{}, derived_unit<metre{}, per<second{}>{}>{}>>
which also is not that nice.
@JohelEGP
JohelEGP
6 hours ago
That's convincing. This justification should definitely be part of the documentation.

View File

@ -1,121 +0,0 @@
.. namespace:: units
Magnitudes
==========
The ratio of two Units of the same Dimension---say, ``inches`` and ``centimeters``---is some
constant number, which is known at compile time. It's a positive real number---a *Magnitude*.
We also use Magnitudes for *Dimensionless* Units. ``percent`` has a Magnitude of :math:`1/100`, and
``dozen`` would have a Magnitude of :math:`12`.
Interestingly, it turns out that the usual numeric types are not up to this task. We need a
Magnitude representation that can do everything Units can do. This means, among other things:
1. We need *exact* symbolic computation of the core operations of Quantity Calculus (i.e., products
and rational powers).
2. We must support *irrational* Magnitudes, because they frequently occur in practice (e.g.,
consider the ratio between ``degrees`` and ``radians``).
3. We should *avoid overflow* wherever possible (note that ``std::intmax_t`` can't even handle
certain simple SI prefixes, such as ``yotta``, representing :math:`10^{24}`).
Integers' inadequacies are clear enough, but even floating point falls short. Imagine if we
implemented all angular units in terms of ``radians``: then both ``degrees`` and ``revolutions``
pick up a factor of :math:`\pi`. The arithmetic with *its floating point representation* is
unlikely to cancel *exactly*.
Another common alternative choice is ``std::ratio``, but this fails the first requirement: rational
numbers are (`rather infamously <https://hsm.stackexchange.com/a/7>`_!) *not* closed under rational
powers.
The only viable solution we have yet encountered is the *vector space representation*. The
implementation is fascinating---but, for purposes of this present page, it's also a distraction.
*Here,* we're more focused on how to *use* these Magnitudes.
One type per Magnitude, one value per type
------------------------------------------
Each typical numeric type (``double``, ``int64_t``, ...) can represent a wide variety of values: the
more, the better. However, Magnitudes are **not** like that. Instead, they comprise a *variety* of
types, and each type can hold only *one* value.
.. tip::
A given Magnitude represents the *same* number, whether you use it as a *type*, or as a *value*
(i.e., an *instance* of that type).
Use whichever is more convenient. (In practice, this is usually the *value*: especially for end
users rather than library developers.)
If these types can only represent one value each, why would we bother to instantiate them? Because
*values are easier to use*.
- ``mag<N>()`` gives the Magnitude value corresponding to any integer ``N``. - You can combine
values in the usual way using ``*``, ``/``, ``==``, and ``!=``, as well as ``pow<N>(m)`` and
``root<N>(m)`` for any Magnitude value ``m``.
Traits: integers and rational Magnitudes
----------------------------------------
If you have a Magnitude instance ``m``, we provide traits to help you reason about integers and
rational numbers, or manipulate integer or rational parts.
- ``is_integral(m)``: indicates whether ``m`` represents an *integral* Magnitude.
- ``is_rational(m)``: indicates whether ``m`` represents a *rational* Magnitude.
The above traits indicate what kind of Magnitude we already have. The next traits *manipulate* a
Magnitude, letting us break it apart into *constituent* Magnitudes which may be more meaningful.
(For example, imagine going from ``inches`` to ``feet``. Naively, we might multiply by the floating
point representation of ``1.0 / 12.0``. However, if we broke this apart into separate numerator and
denominator, it would let us simply *divide by 12*, yielding **exact** results for inputs that
happen to be multiples of 12.)
- ``numerator(m)`` (value): a Magnitude representing the "numerator", i.e., the largest integer
which divides ``m``, without turning any of its base powers' exponents negative (or making any
previously-negative exponents *more* negative). - ``denominator(m)`` (value): the "numerator" of
the *inverse* of ``m``.
These traits interact as one would hope. For example, ``is_rational(m)`` is exactly equivalent to
``m == numerator(m) / denominator(m)``.
Why these particular definitions? Because they are equivalent to the numerator and denominator when
we have a rational number, and they are compatible with how humans write numbers when we don't.
Example:
- :math:`m1 = \frac{27 \pi^2}{25}`. Then ``numerator(m1) == mag<27>()``, and
``denominator(m1) == mag<25>()``.
- :math:`m2 = \sqrt{m1}`. Then ``numerator(m2) == mag<3>()``, and ``denominator(m2) == mag<5>()``.
Note that this is consistent with how humans would typically write ``m2``, as
:math:`\frac{3\sqrt{3} \pi}{5}`.
Getting values out
------------------
Magnitude types represent numbers in non-numeric types. They've got some amazing strengths (exact
rational powers!), and some significant weaknesses (no support for basic addition!). So what if you
just want to turn a Magnitude ``m`` into a traditional numeric type ``T``?
You call ``get_value<T>(m)``.
This does what it looks like it does, and it does it at compile time. Any intermediate computations
take place in the "widest type in category"---``long double`` for floating point, and
``std::intmax_t`` or ``std::uintmax_t`` for signed or unsigned integers---before ultimately being
cast back to the target type. For ``T = float``, say, this means we get all the precision we'd have
with something like ``long double``, but without any speed penalty at runtime!
``get_value<T>(m)`` also has the protections you would hope: for example, if ``T`` is an integral
type, we require ``is_integral(m)``.
How to use Magnitudes
---------------------
- First, start with your basic inputs: this will typically be ``mag<N>()`` for any integer ``N``, or
the built-in Magnitude constant ``mag_pi``. (Again, these are all *values*, not types.)
- Next, combine and manipulate these using the various "Magnitude math" operations, all of which are
**exact**: ``*``, ``/``, ``pow<N>``, ``root<N>``, ``numerator()``, ``denominator()``.
- If you need to translate a Magnitude ``m`` to a "real" numeric type ``T``, call
``get_value<T>(m)``.

View File

@ -1,643 +0,0 @@
.. namespace:: units
Quantities
==========
A :term:`quantity` is a concrete amount of a unit for a specified dimension
with a specific representation and is represented in the library with a
`quantity` class template.
Construction
------------
To create the quantity object from a :term:`scalable number` we just have to pass
the value to the `quantity` class template explicit constructor::
quantity<si::dim_length, si::kilometre, double> d(123);
quantity<si::dim_speed, si::kilometre_per_hour, int> v(70);
.. note::
As the constructor is explicit, the quantity object can be created from
an "unsafe" fundamental type only via
`direct initialization <https://en.cppreference.com/w/cpp/language/direct_initialization>`_.
This is why the code below using
`copy initialization <https://en.cppreference.com/w/cpp/language/copy_initialization>`_
**does not compile**::
quantity<si::dim_length, si::kilometre, double> d = 123; // ERROR
Quantity Construction Helpers
-----------------------------
.. important::
Currently the library provides multiple experimental helpers to instantiate
quantities of different dimensions and units. Users are encourages to try them
out, vote, and share feedback in this
`discussion on GitHub <https://github.com/mpusz/units/discussions/274>`_.
Most probably only one of the options will be included in the final product so
please do not hesitate to vote on the one that suits you the best.
Dimension-Specific Aliases (Experimental)
+++++++++++++++++++++++++++++++++++++++++
To simplify `quantity` objects creation the library provides helper aliases for
quantities of each :term:`dimension` which additionally set the representation
type to ``double`` by default::
namespace si {
template<Unit U, Representation Rep = double>
using length = quantity<dim_length, U, Rep>;
template<Unit U, Representation Rep = double>
using speed = quantity<dim_speed, U, Rep>;
}
Thanks to that, the above example can be rewritten as follows::
si::length<si::kilometre> d(123);
si::speed<si::kilometre_per_hour, int> v(70);
Unit-Specific Aliases (Experimental)
++++++++++++++++++++++++++++++++++++
Additionally to the dimension-specific aliases there are also ones provided for
each and every :term:`unit` in the library::
#ifndef UNITS_NO_ALIASES
namespace units::aliases::isq::si::inline length {
template<Representation Rep = double> using m = units::isq::si::length<units::isq::si::metre, Rep>;
template<Representation Rep = double> using km = units::isq::si::length<units::isq::si::kilometre, Rep>;
}
namespace units::aliases::isq::si::inline speed {
template<Representation Rep = double> using m_per_s = units::isq::si::speed<units::isq::si::metre_per_second, Rep>;
template<Representation Rep = double> using km_per_h = units::isq::si::speed<units::isq::si::kilometre_per_hour, Rep>;
}
#endif // UNITS_NO_ALIASES
Using the above our code can look as follows::
using namespace units::aliases::isq;
si::length::km<> d(123);
si::speed::km_per_h<int> v(70);
Please note that with the C++20 :abbr:`CTAD (Class Template Argument Deduction)` support
for alias templates the above can be rewritten as::
using namespace units::aliases::isq;
si::length::km d(123.);
si::speed::km_per_h v(70);
which will deduce the representation type automatically from the initializer provided
by the user.
Also, this feature allows to be more terse if desired::
using namespace units::aliases::isq::si;
auto d = km(123.);
auto v = km_per_h(70);
Quantity References (Experimental)
++++++++++++++++++++++++++++++++++
Quantity References provide an alternative and simplified way to create quantities.
They are defined using the `reference` class template::
#ifndef UNITS_NO_REFERENCES
namespace length_references {
inline constexpr auto km = reference<dim_length, kilometre>{};
} // namespace length_references
namespace time_references {
inline constexpr auto h = reference<dim_time, hour>{};
} // namespace time_references
namespace references {
using namespace length_references;
using namespace time_references;
} // namespace references
#endif // UNITS_NO_REFERENCES
With the above our code can look as follows::
using namespace units::isq::si::references;
auto d = 123. * km; // si::length<si::kilometre, double>
auto v = 70 * (km / h); // si::speed<si::kilometre_per_hour, int>
.. important::
The following syntaxes are not allowed:
``2 / s``, ``km * 3``, ``s / 4``, ``70 * km / h``.
It is also possible to easily define custom quantity references from existing ones::
inline constexpr auto Nm = N * m;
inline constexpr auto km_per_h = km / h;
inline constexpr auto mph = mi / h;
User Defined Literals (Experimental)
++++++++++++++++++++++++++++++++++++
Alternatively, to construct quantities with compile-time known values the library provides
:abbr:`UDL (User Defined Literal)` s for each :term:`unit` of every :term:`dimension`::
#ifndef UNITS_NO_LITERALS
inline namespace literals {
constexpr auto operator"" _q_km(unsigned long long l) { return length<kilometre, std::int64_t>(l); }
constexpr auto operator"" _q_km(long double l) { return length<kilometre, long double>(l); }
constexpr auto operator"" _q_km_per_h(unsigned long long l) { return speed<kilometre_per_hour, std::int64_t>(l); }
constexpr auto operator"" _q_km_per_h(long double l) { return speed<kilometre_per_hour, long double>(l); }
}
#endif // UNITS_NO_LITERALS
Thanks to them the same code can be as simple as::
using namespace units::isq::si::literals;
auto d = 123._q_km; // si::length<si::kilometre, long double>
auto v = 70_q_km_per_h; // si::speed<si::kilometre_per_hour, std::int64_t>
.. note::
``123._q_km`` should be read as a quantity of length in kilometers. Initially the
library did not use the ``_q_`` prefix for UDLs but it turned out that there are
a few unit symbols that collide with literals already existing in C and C++
language (i.e. ``F`` (farad), ``J`` (joule), ``W`` (watt), ``K`` (kelvin),
``d`` (day), ``l`` or ``L`` (litre), ``erg``, ``ergps``). This is why the
``_q_`` prefix was consistently applied to all the UDLs.
UDLs vs Quantity References
+++++++++++++++++++++++++++
UDLs are helpful but they also have some disadvantages compared to Quantity References:
1. UDLs are only for compile-time known values and do not work for runtime variables
- UDLs::
using namespace units::isq::si::literals;
auto v1 = 120_q_km / 2_q_h;
auto v2 = length<kilometre>(distance) / time<hour>(duration);
- Quantity References::
using namespace units::isq::si::references;
auto v1 = 120 * km / (2 * h);
auto v2 = distance * (1 * km) / (duration * (1 * h));
References treat both cases in a unified way. It is also worth to notice that we work
mostly with runtime variables and compile-time known values mostly appear only in physical
constants and unit tests.
2. UDLs cannot be disambiguated with a namespace name
- UDLs::
using namespace units::isq::si::literals;
using namespace units::isq::si::cgs::literals;
auto d = 1_q_cm; // FAILS TO COMPILE
- Quantity References::
inline constexpr auto si_cm = units::isq::si::references::cm;
inline constexpr auto cgs_cm = units::isq::si::cgs::references::cm;
auto d1 = 1. * si_cm; // si::length<si::centimetre>
auto d2 = 1. * cgs_cm; // si::cgs::length<si::centimetre>
3. Poor control over the representation types as UDLs return only ``std::int64_t`` or
``long double``
- UDLs::
using namespace units::isq::si::literals;
auto d1 = 123._q_km; // si::length<si::kilometre, long double>
auto d2 = 123_q_km; // si::length<si::kilometre, std::int64_t>
No possibility to obtain any other representation type. Additionally this gets contagious
as the result of every arithmetic expression on quantities is always expanded to the common
type of its arguments. For example `si::length<si::metre, int>(1) + 1_q_m` results in a
`si::length<si::metre, int64_t>` type.
- Quantity References::
using namespace units::isq::si::references;
auto d1 = 123. * km; // si::length<si::kilometre, double>
auto d2 = 123 * km; // si::length<si::kilometre, int>
auto d3 = 123.f * km; // si::length<si::kilometre, float>
auto d4 = 123.L * km; // si::length<si::kilometre, long double>
auto d5 = 123ul * km; // si::length<si::kilometre, unsigned long>
auto d6 = 123ll * km; // si::length<si::kilometre, long long>
4. UDLs are verbose to define and standardize
- UDLs:
- for each unit an integral and a floating-point UDL have to be defined
- have to be provided for unnamed derived units (i.e. ``_q_km_per_h``)
- Quantity References:
- one reference per unit
- unnamed derived units are constructed from base references so no explicit
definition is required (i.e. ``km / h``)
5. Typical UDL definition for quantities when compiled with a ``-Wsign-conversion``
flag results in a compilation warning. This warning could be silenced with a
``static_cast<std::int64_t>(value)`` in every UDL, but in a such case other safety
and security issues could be silently introduced.
Quantity References, on the opposite, always use the exact representation type provided
by the user so there is no chance for a truncating conversion on a quantity construction.
6. UDLs take long to compile
- UDLs:
Every unit requires two UDLs to be defined which in turns requires two instantiations
of "heavy" `quantity` class template. Those are then not often used by non-UDL construction
as most users instantiate `quantity` class template with `int` or `double` which
again have to be separately instantiated. This has a significant impact on the compile-time
performance.
- Quantity References:
`reference` class template is "cheaper" to instantiate. Additionally, every unit requires
only one instantiation of a `reference` class template. Such pre-defined reference instance
is then shared among all the instantiations of `quantity` class template for this specific
unit (no matter of its representation type). With this approach we end up with much less class
template instantiations in the application.
Quantity References vs Unit-specific Aliases
++++++++++++++++++++++++++++++++++++++++++++
1. Shadowing issues
- Quantity References
References occupy a pool of many short identifiers which sometimes shadow the variables,
function arguments, or even template parameters provided by the user or other libraries. This
results in warnings being generated by some compilers. The most restrictive here is MSVC which
for example emits a warning of shadowing ``N`` template parameter for an array size provided
in a header file with Newton unit included via namespace declaration in the ``main()`` program
function (see `experimental_angle <https://github.com/mpusz/units/blob/master/example/references/experimental_angle.cpp>`_).
In other cases user is forced to rename its local identifiers to not collide with predefined
references (see `capacitor_time_curve <https://github.com/mpusz/units/blob/master/example/references/capacitor_time_curve.cpp>`_).
- Unit-specific Aliases
As aliases are defined in terms of types rather variables no major shadowing issues were found
so far. In case of identifiers ambiguity it was always possible to disambiguate with more
namespaces prefixed in front of the alias.
2. Adjustable verbosity
- Quantity References
References allow creating custom helpers for complex units. Instead of typing::
static_assert(2 * km / (2 * (km / h)) == 1 * h);
one can do the following::
inline constexpr auto kmph = km / h;
static_assert(2 * km / (2 * kmph) == 1 * h);
- Unit-specific Aliases
There is no need to create custom helpers for complex units as most of them are predefined in
a library already. However, this feature also allows controlling verbosity of the code. For
example in the below example ``d1``, ``d2``, and ``d3`` will end up being of the same type
and having the same value::
auto d1 = m(123.45);
double a = 123.45;
auto d2 = m(a);
auto d3 = length::m(a);
3. Readability
- Quantity References
As long as references are easy to understand in the following code::
auto d = 123 * m;
it is not that nice when a variable is used instead of a compile time number::
constexpr Speed auto avg_speed(double d, double t)
{
using namespace units::isq::si::length_references;
using namespace units::isq::si::time_references;
return d * m / (t * s);
}
Notice that if ``using namespace units::isq::si::references;`` was used instead above it could
cause a clash of ``t`` function parameter with ``si::tonne`` unit symbol if ``si/mass.h`` was
included.
- Unit-specific Aliases
The same using aliases can look as follows::
constexpr Speed auto avg_speed(double d, double t)
{
using namespace units::aliases::isq::si;
return m(d) / s(t);
}
or::
constexpr Speed auto avg_speed(double d, double t)
{
using namespace units::aliases::isq::si;
return length::m(d) / time::s(t);
}
4. Operators Precedence
- Quantity References
The syntax for references uses ``*`` operator which has some predefined precedence. This operator
always takes a magnitude or a reference as ``lhs`` and a reference as ``rhs``. All other combinations
are not allowed. It means that in order to satisfy the operators precedence sometimes quite a lot
of parenthesis have to be sprinkled in the code in order for the code to compile::
static_assert(2 * km / (2 * (km / h)) == 1 * h);
- Unit-specific Aliases
Aliases do not use operator syntax thus they are not affected by the precedence issue.
5. Composition for unnamed derived units
- Quantity References
References have only to be defined for named units. Also for the user's convenience references are
predefined for units raised to a specific power (e.g. ``m2``, ``km3``, etc). All other derived units
can be constructed using the provided ones already even if they do not correspond to any predefined
dimension::
inline constexpr auto kmph = km / h;
inline constexpr auto kmph3 = kmph * kmph * kmph;
- Unit-specific Aliases
Such a feature is not possible with aliases. In order to create a derived unit a full alias template
has to be explicitly provided::
template<Representation Rep = double> using km_per_h = units::isq::si::speed<units::isq::si::kilometre_per_hour, Rep>;
6. Explicit control over the representation type
Both options here allow to preserve user provide representation type but only aliases allow
to override it if needed.
7. Simplified quantity casting
Aliases can easily replace ``quantity_cast<Unit>()`` which is not possible with references::
constexpr auto meter = 1 * m;
std::cout << " = " << quantity_cast<si::international::foot>(meter) << '\n';
The above code for references may look as follows::
constexpr auto meter = m(1);
std::cout << " = " << international::ft(meter) << '\n';
std::cout << " = " << ft(meter) << '\n';
The above will preserve the representation type of the source type.
8. Compilation performance
For our experiments it seems that aliases are 2-5x faster to compile than references (declaring an
alias template is much faster than instantiating a class template).
Summary
+++++++
+-----------------------------------------------+-------------+------------+---------------+
| Feature | Aliases | References | UDLs |
+===============================================+=============+============+===============+
| Literals and variables support | **Yes** | **Yes** | Literals only |
+-----------------------------------------------+-------------+------------+---------------+
| Preserves user provided representation type | **Yes** | **Yes** | No |
+-----------------------------------------------+-------------+------------+---------------+
| Explicit control over the representation type | **Yes** | No | No |
+-----------------------------------------------+-------------+------------+---------------+
| Possibility to resolve ambiguity | **Yes** | **Yes** | No |
+-----------------------------------------------+-------------+------------+---------------+
| Readability | **Good** | Medium | **Good** |
+-----------------------------------------------+-------------+------------+---------------+
| Hard to resolve shadowing issues | **No** | Yes | **No** |
+-----------------------------------------------+-------------+------------+---------------+
| Operators precedence issue | **No** | Yes | **No** |
+-----------------------------------------------+-------------+------------+---------------+
| Controlled verbosity | **Yes** | No | No |
+-----------------------------------------------+-------------+------------+---------------+
| Easy composition for derived units | No | **Yes** | No |
+-----------------------------------------------+-------------+------------+---------------+
| Simplified quantity casting | **Yes** | No | No |
+-----------------------------------------------+-------------+------------+---------------+
| Implementation and standardization effort | Medium | **Lowest** | Highest |
+-----------------------------------------------+-------------+------------+---------------+
| Compile-time performance | **Fastest** | Medium | Slowest |
+-----------------------------------------------+-------------+------------+---------------+
Don't pay for what you don't use (compile-time performance)
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
As noted in the previous chapter, each quantity creation helper has a different impact on the compile-time
performance. Aliases tend to be the fastest to compile but even their definition can be expensive for some
if it is not used in the source code. This is why it is possible to opt-out from each or every quantity
creation helper with the following preprocessor defines::
#define UNITS_NO_ALIASES
#define UNITS_NO_REFERENCES
#define UNITS_NO_LITERALS
Dimension-specific Concepts
---------------------------
In case the user does not care about the specific unit and representation but
requires quantity of a concrete dimension than dimension-specific concepts can
be used::
using namespace units::isq::si::references;
constexpr Length auto d = 123 * km; // si::length<si::kilometre, int>
.. note::
All instances of `quantity` class always match the `Quantity` concept.
All other regular types that are not quantities are called
:term:`scalable numbers <scalable number>` by the library and match the
`Representation` concept.
However, the above is not the most important usage of those concepts. Let's
assume that the user wants to implement an ``avg_speed`` function that will
be calculating the average speed based on provided distance and duration
quantities. The usage of such a function can look as follows::
using namespace units::isq::si::references;
using namespace units::isq::si::international::references;
constexpr Speed auto v1 = avg_speed(220 * km, 2 * h);
constexpr Speed auto v2 = avg_speed(140 * mi, 2 * h);
In this and all other physical units libraries such a function can be
implemented as::
constexpr si::speed<si::metre_per_second> avg_speed(si::length<si::metre> d,
si::time<si::second> t)
{
return d / t;
}
While being correct, this function performs unnecessary intermediate
conversions (from kilometers to meters, from hours to seconds,
and from meters per second to kilometers per hour) which can affect
runtime performance and the precision of the final result. To eliminate
all that overhead we have to write a template function::
template<typename U1, typename R1, typename U2, typename R2>
constexpr auto avg_speed(si::length<U1, R1> d, si::time<U2, R2> t)
{
return d / t;
}
This function will work for every SI unit and representation without any
unnecessary overhead. It is also simple enough to prove its implementation
being correct just by a simple inspection. However, it might not always be
the case. For more complicated calculations we would like to ensure that we
are returning a physical quantity of a correct dimension. For this
dimension-specific concepts come handy again and with usage of C++20 generic
functions our function can look as simple as::
constexpr Speed auto avg_speed(Length auto d, Time auto t)
{
return d / t;
}
Now we are sure that the dimension of returned quantity is correct. Also
please note that with the above code we implemented a truly generic function
that works efficiently not only with SI units but also with other systems of
units like CGS.
.. seealso::
Please refer to :ref:`examples/basics/avg_speed:avg_speed` example for more
information on different kinds of interfaces supported by the library.
Working With Constrained Deduced Quantity Types
-----------------------------------------------
It is important to note that when we assign a result from the function to an
automatically deduced type, even if it is constrained by a dimension-specific
concept, we still do not know what is the exact unit and representation type
of such a quantity. In many cases it might be exactly what we want to get,
but often we would like to know a specific type too. We have two options here:
- query the actual dimension, unit, and representation types::
constexpr Speed auto v = avg_speed(220 * km, 2 * h);
using quantity_type = decltype(v);
using dimension_type = quantity_type::dimension;
using unit_type = quantity_type::unit;
using rep_type = quantity_type::rep;
- convert or cast to a desired quantity type::
constexpr Speed auto v1 = avg_speed(220. * km, 2 * h);
constexpr si::speed<si::metre_per_second> v2 = v1;
constexpr Speed auto v3 = quantity_cast<si::speed<si::metre_per_second>(v1);
.. seealso::
More information on this subject can be found in the
:ref:`framework/conversions_and_casting:Conversions and Casting` chapter.
Dimensionless Quantities
------------------------
Whenever we divide two quantities of the same dimension we end up with a
:term:`dimensionless quantity` otherwise known as :term:`quantity of dimension one`::
static_assert(10 * km / (5 * km) == 2);
static_assert(std::is_same_v<decltype(10 * km / (5 * km)), quantity<dim_one, one, int>>);
According to the official ISO definition `dim_one` is a dimension "for which all the
exponents of the factors corresponding to the base quantities in its quantity dimension
are zero".
.. seealso::
Reasoning for the above design is provided in
:ref:`faq:Why a dimensionless quantity is not just an fundamental arithmetic type?`
To simplify the usage of the dimensionless quantity a following concept and alias template
are provided::
template<typename T>
concept Dimensionless = QuantityOf<T, dim_one>;
template<Unit U, Representation Rep = double>
using dimensionless = quantity<dim_one, U, Rep>;
There are two special units provided for usage with such a quantity:
- `one` which is the :term:`coherent derived unit` of dimensionless quantity and does not
provide any textual symbol (according to the ISO definition "the measurement units and
values of quantities of dimension one are numbers"),
- `percent` which has the symbol ``%`` and ``ratio(1, 100)`` of the `one` unit.
For example the following code::
std::cout << quantity_cast<percent>(50. * m / (100. * m)) << '\n';
will print ``50 %`` to the console output.
Again, according to the ISO definition "such quantities convey more information than a
number". This is exactly what we observe in the above example. The value stored inside
the quantity, the text output, and the value returned by the `quantity::number()` member
function is ``50`` rather than ``0.5``. It means that dimensionless quantities behave
like all other quantities and store the value in terms of a ratio of a coherent unit.
This allows us to not loose precision when we divide quantities of the same dimensions
but with units having vastly different ratios, e.g.
`Dimensionless Hubble parameter <https://en.wikipedia.org/wiki/Hubble%27s_law#Dimensionless_Hubble_parameter>`_
is expressed as a ratio of kilometers and megaparsecs.
.. seealso::
More information on dimensionless quantities can be found in the
:ref:`framework/conversions_and_casting:Implicit conversions of dimensionless quantities`
chapter.

View File

@ -1,77 +0,0 @@
.. namespace:: units
Quantity Kinds
==============
A quantity kind is a quantity of more specific usage.
It is represented in the library with a `quantity_kind` class template.
Kind Creation
-------------
We need a `kind` to represent the more specific usage of a quantity::
struct radius : kind<radius, si::dim_length> {};
Quantities of kind ``radius`` represent a radius.
They are clearly distinct from more generic usages of length quantities.
Construction
------------
To create the quantity kind object from a `quantity` we just have to pass
the value to the `quantity_kind` class template constructor::
quantity_kind<radius, si::kilometre, double> d(123 * km);
.. note::
As the constructor without the kind argument is explicit,
the quantity object can be created from a quantity only via
`direct initialization <https://en.cppreference.com/w/cpp/language/direct_initialization>`_.
This is why the code below using
`copy initialization <https://en.cppreference.com/w/cpp/language/copy_initialization>`_
**does not compile**::
quantity_kind<radius, si::kilometre, double> d = 123 * km; // ERROR
Differences To Quantity
-----------------------
The library provides:
- no kinds, such as ``radius`` or ``width``, therefore
* no UDLs or quantity references,
* no kind-specific concepts, such as ``Radius``,
(there's the generic `QuantityKind` and kind-specifiable `QuantityKindOf`),
- a slightly larger set of operations on quantity kinds
(see the :ref:`framework/dimensions:Quantity Kinds` chapter).
Quantity Point Kinds
--------------------
A quantity point kind is the analogous of a quantity point for quantity kinds
(see the :ref:`framework/quantity_points:Quantity Points` chapter).
They are represented in the library with a `quantity_point_kind` class template.
First, we need a `point_kind` for a `kind`::
struct width : kind<width, si::dim_length> {};
struct x_coordinate : point_kind<x_coordinate, width> {};
Now ``x`` coordinates can be constructed::
quantity_point_kind<x_coordinate, si::metre, int> auto x_pos(123 * m); // QuantityPointKindOf<x_coordinate>
auto x = x_pos.relative(); // quantity_kind<width, si::metre, int>(123 * m)
.. seealso::
Please refer to :ref:`examples/basics/glide_computer:glide_computer` example for more
information on the quantity kinds usage.

View File

@ -1,51 +0,0 @@
.. namespace:: units
Quantity-like Types
===================
.. raw:: html
<object data="../_images/quantity_like.svg" type="image/svg+xml" class="align-center" style="max-width: 100%;"></object>
..
https://www.planttext.com
@startuml
skinparam monochrome true
skinparam shadowing false
skinparam backgroundColor #fcfcfc
hide members
hide circle
class quantity [[../framework/quantities.html]]
class quantity_point [[../framework/quantity_points.html]]
class quantity_kind [[../framework/quantity_kinds.html]]
class quantity_point_kind [[../framework/quantity_kinds.html#quantity-point-kinds]]
Rep <-- quantity : number()
quantity <-- quantity_point : relative()
quantity <-- quantity_kind : common()
quantity_kind <-- quantity_point_kind : relative()
@enduml
[ISO80000]_ defines a :term:`quantity` as a:
Property of a phenomenon, body, or substance, where the property has a magnitude that can be expressed by
means of a number and a reference.
You can use `quantity::number()` member function to get a concrete amount of a unit expressed with a specific
representation type ``Rep``.
:term:`Kind of quantity <kind of quantity>` is defined as:
Aspect common to mutually comparable quantities.
We can obtain a `quantity` with a `quantity_kind::common()` member function.
`quantity_point` and `quantity_point_kind` are absolute quantities and quantity kinds relative to some
specific origin. `quantity` and `quantity_point` types can be obtained from them using a ``relative()`` member
function (`quantity_point::relative()`, `quantity_point_kind::relative()`).

View File

@ -1,52 +0,0 @@
.. namespace:: units
Quantity Points
===============
A quantity point is an absolute quantity with respect to an origin
and is represented in the library with a `quantity_point` class template.
Point Origins
-------------
We need a `point_origin` to represent the origin of a quantity point::
struct mean_sea_level : point_origin<si::dim_length> {};
Quantities points with this origin represent a point from the mean sea level.
The library offers a `dynamic_origin<Dimension>`
for quantity points whose origin is not specified in the type system.
Construction
------------
To create the quantity point object from a `quantity` we just have to pass
the value to the `quantity_point` class template explicit constructor::
quantity_point<dynamic_origin<si::dim_length>, si::kilometre, double> d(123 * km);
.. note::
As the constructor is explicit, the quantity object can be created from
a quantity only via
`direct initialization <https://en.cppreference.com/w/cpp/language/direct_initialization>`_.
This is why the code below using
`copy initialization <https://en.cppreference.com/w/cpp/language/copy_initialization>`_
**does not compile**::
quantity_point<dynamic_origin<si::dim_length>, si::kilometre, double> d = 123 * km; // ERROR
Differences To Quantity
-----------------------
Unlike `quantity`, the library provides:
- no helper aliases for quantity points, such as ``length_point``,
- no UDLs for quantity points,
- no dimension-specific concepts, such as ``LengthPoint``
(there's the dimension-agnostic `QuantityPoint`),
- a more limited set of operations on quantity points
(see the :ref:`framework/arithmetics:Quantity Points` chapter)

View File

@ -1,224 +0,0 @@
.. namespace:: units
Text Output
===========
Beside providing dimensional analysis and units conversions, the library
also tries really hard to print any quantity in the most user friendly way.
.. note::
The library provides no text output for
quantity points or quantity (point) kinds.
Output Streams
--------------
.. tip::
The streaming support is provided via the ``<units/quantity_io.h>`` header file.
The easiest way to print a quantity is to provide its object to the output
stream::
using namespace units::isq::si::references;
using namespace units::isq::si::international::references;
constexpr Speed auto v1 = avg_speed(220. * km, 2 * h);
constexpr Speed auto v2 = avg_speed(140. * mi, 2 * h);
std::cout << v1 << '\n'; // 110 km/h
std::cout << v2 << '\n'; // 70 mi/h
The text output will always print the :term:`value of a quantity` followed
by a space and then the symbol of a :term:`unit` associated with this quantity.
.. important::
Remember that it is a good practice to always `quantity_cast()` a quantity
of an unknown ``auto`` type before passing it to the text output::
std::cout << quantity_cast<si::kilometre_per_hour>(v1) << '\n'; // 110 km/h
std::cout << quantity_cast<si::metre_per_second>(v1) << '\n'; // 30.5556 m/s
Stream Output Formatting
^^^^^^^^^^^^^^^^^^^^^^^^
Only a basic formatting can be applied for output streams. It includes control
over width, fill, and alignment::
os << "|" << std::setw(10) << 123 * m << "|"; // | 123 m|
os << "|" << std::setw(10) << std::left << 123 * m << "|"; // |123 m |
os << "|" << std::setw(10) << std::setfill('*') << 123 * m << "|"; // |*****123 m|
std::format
-----------
.. tip::
The text formatting support is provided via the ``<units/format.h>`` header file.
The **mp-units** via ``std::format`` provides a fine-grained control over what
and how is being printed on the text output.
Grammar
^^^^^^^
.. productionlist::
units-format-spec: [fill-and-align] [width] [units-specs]
units-specs: conversion-spec
: units-specs conversion-spec
: units-specs literal-char
literal-char: any character other than '{' or '}'
conversion-spec: '%' units-type
units-type: [units-rep-modifier] 'Q'
: [units-unit-modifier] 'q'
: one of "nt%"
units-rep-modifier: [sign] [#] [precision] [L] [units-rep-type]
units-rep-type: one of "aAbBdeEfFgGoxX"
units-unit-modifier: 'A'
In the above grammar:
- ``fill-and-align``, ``width``, ``sign``, ``#``, ``precision`` and ``L`` tokens and
individual tokens of :token:`units-rep-type` are defined in the
`format.string.std <https://wg21.link/format.string.std>`_ chapter of the C++
standard specification,
- tokens ``Q``, ``q``, ``n``, ``t``, and ``%`` of :token:`units-type` are described
in the `time.format <https://wg21.link/time.format>`_ chapter of the C++ standard
specification,
- ``A`` token of :token:`units-unit-modifier` forces ASCII-only output (instead of the
default Unicode symbols defined by the :term:`SI` specification).
Default formatting
^^^^^^^^^^^^^^^^^^
To format `quantity` values the formatting facility uses :token:`units-format-spec`.
In case it is left empty the default formatting of ``{:%Q %q}`` is applied. The same
default formatting is also applied to the output streams. This is why the following
code lines produce the same output::
std::cout << "Distance: " << 123 * km << "\n";
std::cout << std::format("Distance: {}\n", 123 * km);
std::cout << std::format("Distance: {:%Q %q}\n", 123 * km);
Quantity Value, Symbol, or Both?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The user can easily decide to either print a whole quantity (value and symbol) or
only its parts. Also a different quantity formatting might be applied::
std::cout << std::format("{:%Q}", 123 * km); // 123
std::cout << std::format("{:%q}", 123 * km); // km
std::cout << std::format("{:%Q%q}", 123 * km); // 123km
Controlling Width, Fill, and Alignment
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
To control width, fill, and alignment the C++ standard grammar tokens ``fill-and-align``
and ``width`` are being used and they treat a quantity value and symbol as a contiguous
text::
std::cout << std::format("|{:0}|", 123 * m); // |123 m|
std::cout << std::format("|{:10}|", 123 * m); // | 123 m|
std::cout << std::format("|{:<10}|", 123 * m); // |123 m |
std::cout << std::format("|{:>10}|", 123 * m); // | 123 m|
std::cout << std::format("|{:^10}|", 123 * m); // | 123 m |
std::cout << std::format("|{:*<10}|", 123 * m); // |123 m*****|
std::cout << std::format("|{:*>10}|", 123 * m); // |*****123 m|
std::cout << std::format("|{:*^10}|", 123 * m); // |**123 m***|
ASCII-only Quantity Symbols
^^^^^^^^^^^^^^^^^^^^^^^^^^^
Unit symbols of some quantities are specified to use Unicode signs by the :term:`SI`
standard (i.e. ``Ω`` symbol for the resistance quantity). **mp-units** library follows
this by default. From the engineering point of view sometimes Unicode text might
not be a solution as terminals of many (especially embedded) devices are ASCII-only.
In such a case the unit symbol can be forced to be printed using ASCII-only characters::
std::cout << std::format("{}", 10 * R); // 10 Ω
std::cout << std::format("{:%Q %Aq}", 10 * R); // 10 ohm
std::cout << std::format("{}", 125 * us); // 125 µs
std::cout << std::format("{:%Q %Aq}", 125 * us); // 125 us
inline constexpr auto s2 = s * s;
std::cout << std::format("{}", 9.8 * (m / s2)); // 9.8 m/s²
std::cout << std::format("{:%Q %Aq}", 9.8 * (m / s2)); // 9.8 m/s^2
Controlling on How the Quantity Value Is Being Printed
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
``sign`` token allows us to specify on how the value's sign is being printed::
std::cout << std::format("{0:%Q %q},{0:%+Q %q},{0:%-Q %q},{0:% Q %q}", 1 * m); // 1 m,+1 m,1 m, 1 m
std::cout << std::format("{0:%Q %q},{0:%+Q %q},{0:%-Q %q},{0:% Q %q}", -1 * m); // -1 m,-1 m,-1 m,-1 m
where:
- ``+`` indicates that a sign should be used for both non-negative and negative numbers,
- ``-`` indicates that a sign should be used for negative numbers and negative zero only
(this is the default behavior),
- ``<space>`` indicates that a leading space should be used for non-negative numbers other
than negative zero, and a minus sign for negative numbers and negative zero.
``precision`` token is allowed only for floating-point representation types::
std::cout << std::format("{:%.0Q %q}", 1.2345 * m); // 1 m
std::cout << std::format("{:%.1Q %q}", 1.2345 * m); // 1.2 m
std::cout << std::format("{:%.2Q %q}", 1.2345 * m); // 1.23 m
:token:`units-rep-type` specifies how a value of the representation type is being
printed. For integral types::
std::cout << std::format("{:%bQ %q}", 42 * m); // 101010 m
std::cout << std::format("{:%BQ %q}", 42 * m); // 101010 m
std::cout << std::format("{:%dQ %q}", 42 * m); // 42 m
std::cout << std::format("{:%oQ %q}", 42 * m); // 52 m
std::cout << std::format("{:%xQ %q}", 42 * m); // 2a m
std::cout << std::format("{:%XQ %q}", 42 * m); // 2A m
The above can be printed in an alternate version thanks to the ``#`` token::
std::cout << std::format("{:%#bQ %q}", 42 * m); // 0b101010 m
std::cout << std::format("{:%#BQ %q}", 42 * m); // 0B101010 m
std::cout << std::format("{:%#oQ %q}", 42 * m); // 052 m
std::cout << std::format("{:%#xQ %q}", 42 * m); // 0x2a m
std::cout << std::format("{:%#XQ %q}", 42 * m); // 0X2A m
For floating-point values the :token:`units-rep-type` token works as follows::
std::cout << std::format("{:%aQ %q}", 1.2345678 * m); // 0x9.e065152d8eae841p-3 m
std::cout << std::format("{:%.3aQ %q}", 1.2345678 * m); // 0x9.e06p-3 m
std::cout << std::format("{:%AQ %q}", 1.2345678 * m); // 0X9.E065152D8EAE841P-3 m
std::cout << std::format("{:%.3AQ %q}", 1.2345678 * m); // 0X9.E06P-3 m
std::cout << std::format("{:%eQ %q}", 1.2345678 * m); // 1.234568e+00 m
std::cout << std::format("{:%.3eQ %q}", 1.2345678 * m); // 1.235e+00 m
std::cout << std::format("{:%EQ %q}", 1.2345678 * m); // 1.234568E+00 m
std::cout << std::format("{:%.3EQ %q}", 1.2345678 * m); // 1.235E+00 m
std::cout << std::format("{:%gQ %q}", 1.2345678 * m); // 1.23457 m
std::cout << std::format("{:%gQ %q}", 1.2345678e8 * m); // 1.23457e+08 m
std::cout << std::format("{:%.3gQ %q}", 1.2345678 * m); // 1.23 m
std::cout << std::format("{:%.3gQ %q}", 1.2345678e8 * m); // 1.23e+08 m
std::cout << std::format("{:%GQ %q}", 1.2345678 * m); // 1.23457 m
std::cout << std::format("{:%GQ %q}", 1.2345678e8 * m); // 1.23457E+08 m
std::cout << std::format("{:%.3GQ %q}", 1.2345678 * m); // 1.23 m
std::cout << std::format("{:%.3GQ %q}", 1.2345678e8 * m); // 1.23E+08 m
Special Signs
^^^^^^^^^^^^^
Beside adding any list of regular characters as a separator between the value and the
symbol, it is possible to type a few special signs there too::
std::cout << std::format("{:%Q_%q}", 123 * km); // 123_km
std::cout << std::format("{:%Q%t%q}", 123 * km); // 123\tkm <tab>
std::cout << std::format("{:%Q%n%q}", 123 * km); // 123\nkm <new line>
std::cout << std::format("{:%Q%% %q}", 123 * km); // 123% km

View File

@ -1,453 +0,0 @@
.. namespace:: units
Units
=====
Each quantity has a magnitude (a numerical value). In order to be able to
compare quantities of the same dimension a notion of a :term:`measurement unit`
was introduced. Units are designated by conventionally assigned names and
symbols. Thanks to them it is possible to compare two quantities of the
same dimension and express the ratio of the second quantity to the first
one as a number. For example ``10 s`` is ``10`` times more than ``1 s``.
Base quantities are expressed in terms of :term:`base units <base unit>`
(i.e. ``m`` (meter), ``s`` (second)), while derived quantities are expressed
in terms of :term:`derived units <derived unit>`.
Class Hierarchy
---------------
All of the described here class templates to produce unit types inherit from some instance
of a `scaled_unit` class template:
.. raw:: html
<object data="../_images/units.svg" type="image/svg+xml" class="align-center" style="max-width: 100%;"></object>
..
https://www.planttext.com
@startuml
skinparam monochrome true
skinparam shadowing false
skinparam backgroundColor #fcfcfc
hide members
hide circle
left to right direction
package Unit <<Frame>> [[../../framework/units.html]] {
abstract scaled_unit<UnitRatio, Unit>
abstract prefixed_alias_unit<Unit, Prefix, AliasUnit> [[../../framework/units.html#aliased-units]]
abstract alias_unit<Unit, Symbol> [[../../framework/units.html#aliased-units]]
abstract derived_scaled_unit<Dimension, Unit, Unit...> [[../../framework/units.html#derived-scaled-units]]
abstract derived_unit [[../../framework/units.html#derived-unnamed-units]]
abstract prefixed_unit<Prefix, Unit> [[../../framework/units.html#prefixed-unit]]
abstract named_scaled_unit<Symbol, Ratio, Unit> [[../../framework/units.html#named-scaled-units]]
abstract named_unit<Symbol> [[../../framework/units.html#base-units]]
scaled_unit <|-- named_unit
scaled_unit <|-- named_scaled_unit
scaled_unit <|-- prefixed_unit
scaled_unit <|-- derived_unit
scaled_unit <|-- derived_scaled_unit
scaled_unit <|-- alias_unit
scaled_unit <|-- prefixed_alias_unit
}
@enduml
`scaled_unit` is a class template used exclusively by the library's framework
and user should not instantiate it by him/her-self. However the user can sometimes
observe this type in case an unit/dimension conversion expression will end up with an
unknown/undefined unit type like in the below example::
using namespace units::isq::si::references;
Length auto l = 100 * (km / h) * (10 * s);
The type of ``l`` above will be
``si::length<scaled_unit<ratio(1, 36, 1), si::metre>, long double>``. This is caused
by the fact that the library does not define a unit of a length quantity that has the
ratio ``10/36`` of a ``si::metre``. If such a unit was predefined we would see its concrete
type here instead.
Base Units
----------
:term:`Base units <base unit>` are the units of
:term:`base quantities <base quantity>` defined for
:term:`base dimensions <base dimension>`. For example in :term:`SI`
``m`` (meter) is a base unit of length, ``s`` (second) is a base unit of
time. In each :term:`coherent system of units`, there is only one base
unit for each base quantity. This is why a base unit type is required by
the `base_dimension` definition in this library. For example ``si::dim_length``
can be defined in the following way::
namespace si {
struct dim_length : base_dimension<"L", metre> {};
}
where ``si::metre`` is defined as::
namespace si {
struct metre : named_unit<metre, "m", prefix> {};
}
In the above definition ``"m"`` is the unit symbol to be used in the text
output, and ``si::prefix`` specifies that the library should allow
definitions of prefixed units using ``si::metre`` as a reference (i.e.
``si::centimetre``).
.. seealso::
For more information on prefixes and scaling please refer to
`Scaled Units`_.
.. note::
The first template argument of `named_unit` is the type of the
child class inherited from the instantiation of this `named_unit`
class template. This is called a
:abbr:`CRTP (Curiously Recurring Template Parameter)` Idiom and is used
in many places in this library to provide
:ref:`design/downcasting:The Downcasting Facility`.
It is important to notice here that :term:`SI` is not the only system used
in the industry and the library has to support other systems too. Also
in some cases conversions between such systems should be allowed. Thanks to
the fact that the `base_dimension` takes the base unit type in its definition
allows us to easily define various systems of units for the same physical
dimension. For example length in the
`CGS <https://en.wikipedia.org/wiki/Centimetre%E2%80%93gram%E2%80%93second_system_of_units>`_
could be defined as::
namespace si::cgs {
struct dim_length : base_dimension<"L", si::centimetre> {};
}
The fact that both base dimensions use the same identifier ``"L"`` tells
the library that both definitions refer to the same physical dimension of
length. The only difference is the measurement unit used to define their
base dimensions. Thanks to using the unit that is defined in terms of the
the same reference unit as the one provided to ``si::dim_length`` definition
(namely ``si::centimetre`` which is ``1/100`` of ``si::metre``) we also enabled
the ability to easily convert between those 2 base dimensions (as the library
knows how to convert ``si::metre`` to ``si::centimetre`` and vice versa).
.. seealso::
More details on custom systems definitions and conversions between
units of the same physical dimension can be found in the
:ref:`use_cases/extensions:Custom Systems` chapter.
Scaled Units
------------
Described above base units (in case of base quantities) and
:term:`coherent units <coherent derived unit>` (in case of derived quantities),
in their system of units, have proportionality factor/ratio equal to one.
However, quantities of such dimensions can also use units of measurement
with other ratios to describe their magnitude (numerical value).
Named Scaled Units
^^^^^^^^^^^^^^^^^^
We are used to use minutes, hours, or days to measure quantities of time.
Those units are the scaled versions of a time dimension's base unit,
namely second. Those can be defined easily in the library using
`named_scaled_unit` class template::
struct minute : named_scaled_unit<minute, "min", ratio(60), second> {};
struct hour : named_scaled_unit<hour, "h", ratio(60), minute> {};
struct day : named_scaled_unit<day, "d", ratio(24), hour> {};
The `ratio` type used in the definition is really similar to ``std::ratio`` but it takes
an additional ``Exponent`` template parameter that defines the exponent of the ratio.
Another important difference is the fact that the objects of that class are used
as class NTTPs rather then a type template parameter kind.
Thanks to it we can address nearly infinite scaling factors between units
and define units like::
struct electronvolt : named_scaled_unit<electronvolt, "eV", prefix,
ratio(1'602'176'634, 1'000'000'000, -19), joule> {};
Finally, the last of the `named_scaled_unit` class template parameters
provide a reference unit for scaling. Please note that it can be a dimension's
base/coherent unit (like ``si::second``) or any other unit (i.e. ``si::minute``,
``si::hour``) that is a scaled version of the dimension's base/coherent unit.
Prefixed Unit
^^^^^^^^^^^^^
Prefixed units are just scaled units with a standardized ratio. For example
:term:`SI` defines prefixes based on the exponent of ``10``. Here is a
complete list of all the :term:`SI` prefixes supported by the library::
namespace si {
struct yocto : prefix<yocto, "y", mag_power<10, -24>()> {};
struct zepto : prefix<zepto, "z", mag_power<10, -21>()> {};
struct atto : prefix<atto, "a", mag_power<10, -18>()> {};
struct femto : prefix<femto, "f", mag_power<10, -15>()> {};
struct pico : prefix<pico, "p", mag_power<10, -12>()> {};
struct nano : prefix<nano, "n", mag_power<10, -9>()> {};
struct micro : prefix<micro, basic_symbol_text{"\u00b5", "u"},
mag_power<10, -6>()> {};
struct milli : prefix<milli, "m", mag_power<10, -3>()> {};
struct centi : prefix<centi, "c", mag_power<10, -2>()> {};
struct deci : prefix<deci, "d", mag_power<10, -1>()> {};
struct deca : prefix<deca, "da", mag_power<10, 1>()> {};
struct hecto : prefix<hecto, "h", mag_power<10, 2>()> {};
struct kilo : prefix<kilo, "k", mag_power<10, 3>()> {};
struct mega : prefix<mega, "M", mag_power<10, 6>()> {};
struct giga : prefix<giga, "G", mag_power<10, 9>()> {};
struct tera : prefix<tera, "T", mag_power<10, 12>()> {};
struct peta : prefix<peta, "P", mag_power<10, 15>()> {};
struct exa : prefix<exa, "E", mag_power<10, 18>()> {};
struct zetta : prefix<zetta, "Z", mag_power<10, 21>()> {};
struct yotta : prefix<yotta, "Y", mag_power<10, 24>()> {};
}
Alternative hierarchy of prefixes is the one used in data information
domain::
namespace iec80000 {
struct kibi : prefix<kibi, "Ki", mag_power<2, 10>()> {};
struct mebi : prefix<mebi, "Mi", mag_power<2, 20>()> {};
struct gibi : prefix<gibi, "Gi", mag_power<2, 30>()> {};
struct tebi : prefix<tebi, "Ti", mag_power<2, 40>()> {};
struct pebi : prefix<pebi, "Pi", mag_power<2, 50>()> {};
struct exbi : prefix<exbi, "Ei", mag_power<2, 60>()> {};
struct zebi : prefix<zebi, "Zi", mag_power<2, 70>()> {};
struct yobi : prefix<yobi, "Yi", mag_power<2, 80>()> {};
}
With the definitions like above we can easily define prefixed unit. For
example we can define ``si::kilometre`` as::
namespace si {
struct kilometre : prefixed_unit<kilometre, kilo, metre> {};
}
.. important::
Prefixed units have to use named units as a reference. For unnamed
units we could end up with some strange, misleading, and sometimes
wrong definitions ("kilo square metre" seams strange and spelled
as ``km²`` would be invalid).
.. note::
[SIBrochure]_ states:
However, when prefixes are used with SI units, the resulting units are no
longer coherent, because the prefix introduces a numerical factor other than one.
Derived Units
-------------
:term:`Derived units <derived unit>` are the units used to measure
:term:`derived quantities <derived quantity>`. They can either have their own unique
names (i.e. ``N`` (newton)) or can be composed from the names of units of quantities
used to define thier derived quantity (i.e. ``km/h``).
The [SIBrochure]_ states:
Derived units are defined as products of powers of the base units. When the numerical
factor of this product is one, the derived units are called coherent derived units. The base
and coherent derived units of the SI form a coherent set, designated the set of coherent SI
units. The word “coherent” here means that equations between the numerical values of
quantities take exactly the same form as the equations between the quantities themselves.
Derived Named Units
^^^^^^^^^^^^^^^^^^^
The [SIBrochure]_ also says:
Some of the coherent derived units in the SI are given special names.
Derived named units have a unique symbol (i.e. ``N`` (newton) or ``Pa``
(pascal)) and they are defined in the same way as base units (which
always have to be a named unit)::
namespace si {
struct newton : named_unit<newton, "N", prefix> {};
}
Derived Unnamed Units
^^^^^^^^^^^^^^^^^^^^^
Derived unnamed units are the units where the symbol is derived from the
base quantities symbols and the expression of the dependence of the derived
quantity on the base quantities (i.e. ``m/s`` (metre per second), ````
(square metre)). To support such use cases a library introduced a notion of
:term:`derived dimension recipe` which stores the information about the
order, exponents, and types of dimensions used to define this particular
derived dimension. For example each of the below ``momentum`` definitions
will result in a different unnamed unit symbol:
.. code-block::
:emphasize-lines: 2-4, 6-8, 10-12
struct dim_momentum : derived_dimension<dim_momentum, kilogram_metre_per_second,
exponent<si::dim_mass, 1>,
exponent<si::dim_length, 1>,
exponent<si::dim_time, -1>> {}; // kg⋅m/s
struct dim_momentum : derived_dimension<dim_momentum, kilogram_metre_per_second,
exponent<si::dim_length, 1>,
exponent<si::dim_mass, 1>,
exponent<si::dim_time, -1>> {}; // m⋅kg/s
struct dim_momentum : derived_dimension<dim_momentum, kilogram_metre_per_second,
exponent<si::dim_time, -1>,
exponent<si::dim_length, 1>,
exponent<si::dim_mass, 1>> {}; // 1/s⋅m⋅kg
where ``kilogram_metre_per_second`` is defined as::
struct kilogram_metre_per_second : derived_unit<kilogram_metre_per_second> {};
However, the easiest way to define momentum is just to use the
``si::dim_speed`` derived dimension in the recipe:
.. code-block::
:emphasize-lines: 3
struct dim_momentum : derived_dimension<dim_momentum, kilogram_metre_per_second,
exponent<si::dim_mass, 1>,
exponent<si::dim_speed, 1>> {}; // kg⋅m/s
In such a case the library will do its magic and will automatically
unpack a provided derived dimension to its base dimensions in order to
end up with a :term:`normalized derived dimension` for a parent entity.
The need to support a derived dimension in the recipe is not just a
syntactic sugar that allows us to do less typing. It is worth to notice
here that some of the derived unnamed units are defined in terms of other
derived named units (i.e. surface tension quantity is measured in terms
of ``N/m``):
.. code-block::
:emphasize-lines: 2
struct dim_surface_tension : derived_dimension<dim_surface_tension, newton_per_metre,
exponent<si::dim_force, 1>,
exponent<si::dim_length, -1>> {}; // N/m
If we defined the above in terms of base units we would end up with
a ``kg/s²`` derived unit symbol.
Derived Scaled Units
^^^^^^^^^^^^^^^^^^^^
For some units determining of a correct scaling ratio may not be trivial,
and even if done correctly, may be a pain to maintain. For a simple example
let's take a "kilometre per hour" unit. What is the easiest to maintain
ratio in reference to the "metre per second":
- ``1000/3600``
- ``10/36``
- ``5/18``
Whichever, we choose there will always be someone not happy with our choice.
Thanks to a `derived_scaled_unit` class template provided by the library this problem
does not exist at all. With it ``si::kilometre_per_hour`` can be defined as::
namespace si {
struct kilometre_per_hour : derived_scaled_unit<kilometre_per_hour, dim_speed, kilometre, hour> {};
}
In case the scaled derived unit should serve as a named one we can use
a `named_derived_unit` where the user is able to provide a symbol for the unit
by him/her-self::
namespace si::fps {
struct knot : named_derived_unit<knot, dim_speed, "knot", nautical_mile, hour> {};
}
Please note that the dervided scaled units are the only unit-related class templates
that take a dimension as its parameter. This derived dimension provides a :term:`recipe`
used for its definition. Based on the information stored in the recipe
(order, type, and exponents of composite dimensions) and the ratios of units
provided in the template parameter list after the derived dimension parameter,
the library calculates the final ratio for this unit.
Aliased Units
-------------
In order to make our life easier people tend to assign alternative/aliased names
to some popular units. As an example we often use "tonne" instead of "megagram",
"litre" instead of "cubic decimetre", or "hectare" instead of "square hectometre".
This library provides facilities to define aliased names to already defined units
with `alias_unit` class template::
namespace si {
struct litre : alias_unit<cubic_decimetre, "l", prefix> {};
}
Also, it is possible to add prefixes to such aliased units with `prefixed_alias_unit`
class template::
namespace si {
struct millilitre : prefixed_alias_unit<cubic_centimetre, milli, litre> {};
}
.. seealso::
To learn more about unknown units please refer to the
:ref:`use_cases/unknown_dimensions:Working with Unknown Dimensions and Their Units` chapter.
## System reference
"It is important to emphasize that each physical quantity has only one coherent SI unit, even
though this unit can be expressed in different forms by using some of the special names and
symbols."
The converse, however, is not true, because in general several different quantities may
share the same SI unit.
For example, for the quantity heat capacity as well as for the
quantity entropy the SI unit is joule per kelvin. Similarly, for the base quantity electric
current as well as the derived quantity magnetomotive force the SI unit is the ampere. It is
therefore important not to use the unit alone to specify the quantity.

View File

@ -1,4 +0,0 @@
.. This file is a placeholder and will be replaced during Sphinx build
Index
#####

View File

@ -0,0 +1,83 @@
# Code Example
Here is a small example of operations possible on scalar quantities:
```cpp
#include <mp-units/systems/si/si.h>
using namespace mp_units::si::unit_symbols;
// simple numeric operations
static_assert(10 * km / 2 == 5 * km);
// unit conversions
static_assert(1 * h == 3600 * s);
static_assert(1 * km + 1 * m == 1001 * m);
// dimension conversions
inline constexpr auto kmph = km / h;
static_assert(1 * km / (1 * s) == 1000 * (m / s));
static_assert(2 * kmph * (2 * h) == 4 * km);
static_assert(2 * km / (2 * kmph) == 1 * h);
static_assert(2 * m * (3 * m) == 6 * m2);
static_assert(10 * km / (5 * km) == 2);
static_assert(1000 / (1 * s) == 1 * kHz);
```
!!! example "[Try it on Compiler Explorer](https://godbolt.org/z/j8afKnarv)"
This library requires some C++20 features ([concepts and constraints](https://en.cppreference.com/w/cpp/language/constraints),
[classes as NTTP](https://en.cppreference.com/w/cpp/language/template_parameters), ...). Thanks to them,
the user gets a powerful but still easy-to-use interface where all unit conversions and dimensional analysis can be
performed without sacrificing accuracy. Please see the below example for a quick preview of basic library features:
*[NTTP]: Non-Type Template Parameter
```cpp
#include <mp-units/format.h>
#include <mp-units/iostream.h>
#include <mp-units/systems/international/international.h>
#include <mp-units/systems/isq/space_and_time.h>
#include <mp-units/systems/si/si.h>
#include <iostream>
using namespace mp_units;
constexpr QuantityOf<isq::speed> auto avg_speed(QuantityOf<isq::length> auto d,
QuantityOf<isq::time> auto t)
{
return d / t;
}
int main()
{
using namespace mp_units::si::unit_symbols;
using namespace mp_units::international::unit_symbols;
constexpr auto v1 = 110 * (km / h);
constexpr auto v2 = 70 * mph;
constexpr auto v3 = avg_speed(220. * isq::distance[km], 2 * h);
constexpr auto v4 = avg_speed(isq::distance(140. * mi), 2 * h);
constexpr auto v5 = v3[m / s];
constexpr auto v6 = value_cast<m / s>(v4);
constexpr auto v7 = value_cast<int>(v6);
std::cout << v1 << '\n'; // 110 km/h
std::cout << v2 << '\n'; // 70 mi/h
std::cout << std::format("{}", v3) << '\n'; // 110 km/h
std::cout << std::format("{:*^14}", v4) << '\n'; // ***70 mi/h****
std::cout << std::format("{:%Q in %q}", v5) << '\n'; // 30.5556 in m/s
std::cout << std::format("{0:%Q} in {0:%q}", v6) << '\n'; // 31.2928 in m/s
std::cout << std::format("{:%Q}", v7) << '\n'; // 31
}
```
!!! example "[Try it on Compiler Explorer](https://godbolt.org/z/T8bovrqTP)"
!!! note
You can find more code examples in the Examples chapter.

176
docs/getting_started/faq.md Normal file
View File

@ -0,0 +1,176 @@
# Frequently Asked Questions
## Why do we spell `metre` instead of `meter`?
This is how ISO 80000 defines it (British English spelling by default).
## Why don't we use UDLs to create quantities?
Many reasons make UDLs a poor choice for a physical units library:
1. UDLs work only with literals (compile-time known values). Our observation is that besides
the unit tests, there are few compile-time known constants used in the production code.
2. Typical implementations of UDLs tend to always use the widest representation type available.
In the case of `std::chrono::duration`, the following is true:
```cpp
using namespace std::chrono_literals;
auto d1 = 42s;
auto d2 = 42.s;
static_assert(std::is_same_v<decltype(d1)::rep, std::int64_t>);
static_assert(std::is_same_v<decltype(d2)::rep, long double>);
```
3. While increasing the coverage for the library, we learned that many unit symbols conflict with
built-in types or numeric extensions. A few of those are: `F` (farad), `J` (joule), `W` (watt),
`K` (kelvin), `d` (day), `l` or `L` (litre), `erg`, `ergps`. For a while for those we used `_` prefix
to make the library work at all, but at some point, we had to unify the naming, and we came up with `_q_`
prefix, which resulted in creating a quantity of a provided unit. So in case the library is
standardized, all quantities would be created with UDLs having `q_` prefix (i.e. `42q_s`)
which is not that nice anymore.
4. UDLs with the same identifiers defined in different namespace can't be disambiguated in the C++
language. If both SI and CGS systems define `_q_s` UDL for a second unit, then it would not be possible
to specify which one to use in case both namespaces are "imported".
5. Another bad property of UDLs is that they do not compose. A coherent unit of angular momentum would
have a UDL specified as `_q_kg_m2_per_s`. Now imagine that you want to make every possible user happy.
How many variations of that unit would you predefine for differently scaled versions of unit ingredients?
6. UDLs are also really expensive to define and specify. For each unit, we need two definitions. One for
integral and another one for floating-point representation. Before the V2 framework, the coherent unit of
angular momentum was defined as:
```cpp
constexpr auto operator"" _q_kg_m2_per_s(unsigned long long l)
{
gsl_ExpectsAudit(std::in_range<std::int64_t>(l));
return angular_momentum<kilogram_metre_sq_per_second, std::int64_t>(static_cast<std::int64_t>(l));
}
constexpr auto operator"" _q_kg_m2_per_s(long double l)
{
return angular_momentum<kilogram_metre_sq_per_second, long double>(l);
}
```
## Why `60 * km / h` does not compile?
The library design does not allow multiplying or dividing a quantity (the result of `60 * km`)
by another unit. This significantly limits the number of possible errors and surprises in the
quantity equations.
Consider the following expression:
```cpp
auto q = 60 * km / 2 * h;
```
Looks like `30 km/h`, right? But it is not. If the above code was allowed, it would result
in `30 km⋅h`. In case you want to divide `60 * km` by `2 * h` a parenthesis is needed
`60 * km / (2 * h)`.
Another surprising issue could result from the following code:
```cpp
template<typename T>
auto make_length(T v) { return v * si::metre; }
auto v = 42;
auto q = make_length(v);
```
The above might look like a good idea, but consider what would happen in the user provided
an already existing quantity:
```cpp
auto v = 42 * m;
auto q = make_length(v);
```
Fortunately, with the current design, such issues are detected at compile-time.
## Why a dimensionless quantity is not just a fundamental arithmetic type?
In the initial design of this library, the resulting type of division of two quantities was their
common representation type:
```cpp
static_assert(std::is_same_v<decltype(10 * km / (5 * km)), std::int64_t>);
```
First of all, this was consistent with
[`std::chrono::duration`](https://en.cppreference.com/w/cpp/chrono/duration/operator_arith4) behavior.
Additional reasoning behind it was not providing a false impression of a strong `quantity` type for
something that looks and feels like a regular number. Also, all of the mathematic and trigonometric functions
were working fine out of the box with such representation types, so we did not have to rewrite
`sin()`, `cos()`, `exp()`, and others.
However, the feedback we got from the production usage was that such an approach is really bad for generic
programming. It is hard to handle the result of the two quantities' division (or multiplication) as
it might be either a quantity or a fundamental type. If we want to raise such a result to some power, we
must use `units::pow` or `std::pow` depending on the resulting type. Those are only a few issues related
to such an approach.
Moreover, suppose you divide quantities of the same dimension but with units of significantly different
magnitudes. In that case, you may end up with a really small or a huge floating-point value, which may result
in losing lots of precision. Returning a dimensionless quantity from such cases allows us to benefit from
all the properties of scaled units and is consistent with the rest of the library.
!!! info
More information on the current design can be found in the Dimensionless Quantities chapter.
## Why Unicode quantity symbols are used by default instead of ASCII-only characters?
Both C++ and ISO 80000 are standardized by the ISO. ISO 80000 and the SI standards specify Unicode symbols
as the official unit names for some quantities (i.e. `Ω` symbol for the resistance quantity).
As **mp-units** library will be proposed for standardization as a part of the C++ Standard Library
we have to obey the rules and be consistent with ISO specifications.
!!! info
We do understand engineering reality and the constraints of some environments. This is why the library
has the option of ASCII-only Quantity Symbols.
## Why don't you have CMake options to disable the building of tests and examples?
Over time many people provided PRs proposing adding options to build tests and examples conditionally.
Here are a few examples:
- [Add CMake options for disabling docs, examples and tests](https://github.com/mpusz/mp-units/pull/124)
- [build: add options to disable part of the build](https://github.com/mpusz/mp-units/pull/402)
- [CMake Refactoring and Option Cleanup](https://github.com/mpusz/mp-units/pull/456)
We admit this is a common practice in the industry, but we also believe this is a bad pattern.
First, the only need for such options comes when a user wants to use `add_subdirectory()` in CMake
to handle dependencies. Such an approach does not scale and should be discouraged. There is little
use for such a practice in times when we have dedicated package managers like Conan.
The second thing is that our observation is that many people are fixed on disabling "unneeded" subdirectories
from compilation, but they do not see or address the biggest issue, which is polluting user's build
environment with our development-specific settings. Propagating our restrictive compilation flags to user's
project is not the best idea as it might cause a lot of harm if this project stops to compile
because of that.
Last but not least, not having those options is on purpose. Top level _CMakeLists.txt_ file should only
be used by **mp-units** developers and contributors as an entry point for project's development.
We want to ensure that everyone will build **ALL** the code correctly before pushing a commit. Having
such options would allow unintended issues to leak to PRs and CI.
This is why our projects have two entry points:
- _./CMakeLists.txt_ is to be used by projects developers to build **ALL** the project code with really
restrictive compilation flags,
- _./src/CMakeLists.txt_ contains only a pure library definition and should be used by the customers
that prefer to use CMake's `add_subdirectory()` to handle the dependencies.
!!! info
For more details on this please refer to the [CMake + Conan: 3 Years Later - Mateusz Pusz](https://youtu.be/mrSwJBJ-0z8?t=1931)
lecture that Mateusz Pusz provided at the C++Now 2021 conference.

View File

@ -0,0 +1,449 @@
# Installation And Usage
!!! info
**mp-units** library tries to provide the best user experience possible with the C++ language.
To achieve that, it extensively uses C++20 features and the
[explicit object parameter](https://en.cppreference.com/w/cpp/language/member_functions#Explicit_object_parameter)
from C++23.
Even though the library benefits from C++23 (if available), C++20 is enough to compile and
use all of the library's functionality. C++23 features are hidden behind a preprocessor macro
providing a backward-compatible way to use it.
Sadly, as of today, not many compilers provide full C++20 support. The library compiles fine
on the following compilers (or newer):
- gcc-12.2
In the upcoming weeks, we will be actively working to extend the support to other compilers as well.
## Repository Structure and Dependencies
This repository contains three independent CMake-based projects:
- _./src_
- header-only project containing whole **mp-units** library
- _./src/CMakeList.txt_ file is intended as an **entry point for library users**
- in case this library becomes part of the C++ standard, it will have no external dependencies
but until then, it depends on the following:
- [gsl-lite](https://github.com/gsl-lite/gsl-lite) to verify runtime contracts with
the `gsl_Expects` macro,
- [{fmt}](https://github.com/fmtlib/fmt) to provide text formatting of quantities
(if `std::format` is not supported yet on a specific compiler),
- [only for clang < 14 with libc++] [range-v3](https://github.com/ericniebler/range-v3)
to provide needed C++20 concepts and utilities.
- _._
- project used as an **entry point for library development and CI/CD**
- it wraps _./src_ project together with usage examples and tests
- additionally to the dependencies of _./src_ project, it uses:
- `Catch2 <https://github.com/catchorg/Catch2>`_ library as a unit tests framework,
- `linear algebra <https://github.com/BobSteagall/wg21/tree/master/include>`_
library based on proposal `P1385 <https://wg21.link/P1385>`_ used in some examples
and tests.
- in case you also want to generate the project's documentation, you will need:
- [Material for MkDocs](https://squidfunk.github.io/mkdocs-material)
- *./test_package*
- library installation and Conan package verification.
!!! tip
Top level _CMakeLists.txt_ file should only be used by **mp-units** developers and contributors
as an entry point for the project's development. We want to ensure that everyone will build **ALL**
the code correctly before pushing a commit. Having such options would allow unintended issues to
leak to PRs and CI.
This is why our projects have two entry points:
- _./CMakeLists.txt_ is to be used by projects developers to build **ALL** the project code with really
restrictive compilation flags,
- _./src/CMakeLists.txt_ contains only a pure library definition and should be used by the customers
that prefer to use CMake's `add_subdirectory()` to handle the dependencies.
To learn more about the rationale, please check our [FAQ](../faq/#why-dont-you-have-cmake-options-to-disable-building-of-tests-and-examples).
## Obtaining Dependencies
This library assumes that most of the dependencies will be provided by the
[Conan Package Manager](https://conan.io/). If you want to obtain required
dependencies by other means, some modifications to the library's CMake files might be needed.
The rest of the dependencies responsible for documentation generation are provided by
`python3-pip`.
### Conan Quick Intro
In case you are not familiar with Conan, to install it (or upgrade) just do:
```shell
pip3 install -U conan
```
After that, you might need to add a custom profile file for your development environment
in _~/.conan2/profiles_ directory. An example profile can look as follows:
```ini hl_lines="5" title="~/.conan2/profiles/gcc12"
[settings]
arch=x86_64
build_type=Release
compiler=gcc
compiler.cppstd=20
compiler.libcxx=libstdc++11
compiler.version=12
os=Linux
[conf]
tools.build:compiler_executables={"c": "gcc-12", "cpp": "g++-12"}
```
!!! tip
Please note that the **mp-units** library requires C++20 to be set in a Conan profile or forced
via the Conan command line. If you do the former, you will not need to provide `-s compiler.cppstd=20`
every time your run a Conan command line (as provided in the command line instructions below).
Additionally, it is recommended to set Ninja as a CMake generator for Conan. To do so, you should create
a _~/.conan2/global.conf_ file that will set `tools.cmake.cmaketoolchain:generator` to one of Ninja
generators. For example:
```text title="~/.conan2/global.conf"
tools.cmake.cmaketoolchain:generator="Ninja Multi-Config"
```
!!! note
_~/.conan2/global.conf_ file may also set `tools.cmake.cmake_layout:build_folder_vars` which
[makes working with several compilers or build configurations easier](https://docs.conan.io/2/reference/tools/cmake/cmake_layout.html#multi-setting-option-cmake-layout).
For example, the below line will force Conan to generate separate CMake presets and folders for
each compiler:
```text title="~/.conan2/global.conf"
tools.cmake.cmake_layout:build_folder_vars=["settings.compiler", "settings.compiler.version"]
```
In such a case, you will need to use a configuration-specific preset name in the Conan instructions
provided below rather then just `conan-default` and `conan-release`
(i.e. `conan-gcc-11` and `conan-gcc-11-release`)
## Build Options
### Conan Configuration Properties
[`user.build:all`](#user-build-all){ #user-build-all }
: [:octicons-tag-24: 0.8.0][build all support] · :octicons-milestone-24: `True`/`False` (Default: `False`)
Enables compilation of all the source code including tests and examples. To support
this it requires some additional Conan build dependencies described in
[Repository Structure and Dependencies](#repository-structure-and-dependencies).
It also runs unit tests during Conan build (unless `tools.build:skip_test`
configuration property is set to `True`).
[build all support]: https://github.com/mpusz/mp-units/releases/tag/v0.8.0
[`user.build:skip_la`](#user-skip-la){ #user-skip-la }
: [:octicons-tag-24: 0.8.0][skip la support] · :octicons-milestone-24: `True`/`False` (Default: `False`)
If `user.build:all` is enabled, among others, Conan installs the external
[wg21-linear_algebra](https://conan.io/center/wg21-linear_algebra)
dependency and enables the compilation of linear algebra-based tests and usage examples.
Such behavior can be disabled with this option.
[skip la support]: https://github.com/mpusz/mp-units/releases/tag/v0.8.0
### CMake Options
[`MP_UNITS_AS_SYSTEM_HEADERS`](#MP_UNITS_AS_SYSTEM_HEADERS){ #MP_UNITS_AS_SYSTEM_HEADERS }
: [:octicons-tag-24: 2.0.0][as system headers support] · :octicons-milestone-24: `ON`/`OFF` (Default: `OFF`)
Exports library as system headers.
[as system headers support]: https://github.com/mpusz/mp-units/releases/tag/v2.0.0
[`MP_UNITS_BUILD_LA`](#MP_UNITS_BUILD_LA){ #MP_UNITS_BUILD_LA }
: [:octicons-tag-24: 2.0.0][build la support] · :octicons-milestone-24: `ON`/`OFF` (Default: `ON`)
Enables building code depending on the linear algebra library.
[build la support]: https://github.com/mpusz/mp-units/releases/tag/v2.0.0
[`MP_UNITS_IWYU`](#MP_UNITS_IWYU){ #MP_UNITS_IWYU }
: [:octicons-tag-24: 2.0.0][iwyu support] · :octicons-milestone-24: `ON`/`OFF` (Default: `OFF`)
Enables `include-what-you-use` when compiling with a clang compiler.
Additionally turns on [`MP_UNITS_AS_SYSTEM_HEADERS`](#MP_UNITS_AS_SYSTEM_HEADERS).
[iwyu support]: https://github.com/mpusz/mp-units/releases/tag/v2.0.0
[`MP_UNITS_USE_LIBFMT`](#MP_UNITS_USE_LIBFMT){ #MP_UNITS_USE_LIBFMT }
: [:octicons-tag-24: 2.0.0][use libfmt support] · :octicons-milestone-24: `ON`/`OFF` (Default: `ON`)
Enables usage of [{fmt}](https://github.com/fmtlib/fmt) library instead of the C++20 Standard
Library feature.
[use libfmt support]: https://github.com/mpusz/mp-units/releases/tag/v2.0.0
## CMake with Presets Support
It is recommended to use at least CMake 3.23 to build this project as this version introduced support
for CMake Presets schema version 4 used now by Conan to generate presets files. All build instructions
below assume that you have such support. If not, your CMake invocations have to be replaced with something
like:
```shell
mkdir build && cd build
cmake .. -G "Ninja Multi-Config" -DCMAKE_TOOLCHAIN_FILE=<path_to_generators_dir>/conan_toolchain.cmake
cmake --build . --config Release
```
!!! note
In case you can't use CMake 3.23 but you have access to CMake 3.20 or later, you can append
`-c tools.cmake.cmaketoolchain.presets:max_schema_version=2` to the `conan install` command
which will force Conan to use an older version of the CMake Presets schema.
## Installation and Reuse
There are many different ways of installing/reusing **mp-units** in your project. Below we mention
only a few of many options possible.
!!! info
The easiest and most recommended way to obtain **mp-units** is with the Conan package manager.
See [Conan + CMake (release)](#conan-cmake-release) for a detailed instruction.
### Copy
As **mp-units** is a C++ header-only library you can simply copy all needed _src/*/include_ subdirectories
to your source tree.
!!! note
In such a case, you are on your own to ensure all the dependencies are installed, and their header
files can be located during the build. Please also note that some compiler-specific flags are needed
to make the code compile without issues.
### Copy + CMake
If you copy the whole **mp-units** repository to your project's file tree, you can reuse CMake targets
defined by the library. To do so, you should use _CMakeLists.txt_ file from the _./src_ directory:
```cmake
add_subdirectory(<path_to_units_folder>/src)
# ...
target_link_libraries(<your_target> <PUBLIC|PRIVATE|INTERFACE> mp-units::mp-units)
```
!!! note
You are still on your own to make sure all the dependencies are installed and their header and CMake
configuration files can be located during the build.
### Conan + CMake (release)
!!! tip
If you are new to the Conan package manager, it is highly recommended to read
[Obtaining Dependencies](#obtaining-dependencies) and refer to
[Consuming packages](https://docs.conan.io/2/tutorial/consuming_packages.html)
chapter of the official Conan documentation for more information.
**mp-units** releases are hosted on [Conan-Center](https://conan.io/center/mp-units).
To obtain an official library release, the following steps may be performed:
1. Create Conan configuration file (either _conanfile.txt_ or _conanfile.py_) in your
project's top-level directory and add **mp-units** as a dependency of your project.
For example, the simplest file may look as follows:
```ini title="conanfile.txt"
[requires]
mp-units/0.8.0
[layout]
cmake_layout
[generators]
CMakeToolchain
CMakeDeps
```
2. Import **mp-units** and its dependencies definitions to your project's build procedure
with `find_package`:
```cmake
find_package(mp-units CONFIG REQUIRED)
```
3. Link your CMake targets with **mp-units**:
```cmake
target_link_libraries(<your_target> <PUBLIC|PRIVATE|INTERFACE> mp-units::mp-units)
```
4. Download, build, and install Conan dependencies before running the CMake configuration step:
```shell
conan install . -pr <your_conan_profile> -s compiler.cppstd=20 -b=missing
cmake --preset conan-default
cmake --build --preset conan-release
```
### Conan + CMake (Live At Head)
This chapter describes the procedure to Live At Head, which means using the latest version
of **mp-units** all the time.
!!! note
Please note that even though the Conan packages that you will be using are generated **ONLY**
for builds that are considered stable (passed our CI tests) some minor regressions may happen
(our CI and C++20 build environment is not perfect yet). Also, please expect that the library
interface might, and probably will, change occasionally. Even though we do our best, such
changes might not be reflected in the project's documentation right away.
The procedure is similar to the one described in [Conan + CMake (release)](#conan-cmake-release)
with the following differences:
1. Before starting the previous procedure, add **mp-units** remote to your Conan configuration:
```shell
conan remote add conan-mpusz https://mpusz.jfrog.io/artifactory/api/conan/conan-oss
```
2. In your Conan configuration file, provide the package identifier of the `mpusz/testing` stream:
```ini title="conanfile.txt" hl_lines="2"
[requires]
mp-units/2.0.0@mpusz/testing
[layout]
cmake_layout
[generators]
CMakeToolchain
CMakeDeps
```
!!! tip
The identifiers of the latest packages can always be found in
[the project's README file](https://github.com/mpusz/mp-units/blob/master/README.md) or on
[the project's Artifactory](https://mpusz.jfrog.io/ui/packages/conan:%2F%2Fmp-units).
3. Force Conan to check for updated recipes with `-u`:
```shell
conan install . -pr <your_conan_profile> -s compiler.cppstd=20 -b=missing -u
```
### Install
In case you don't want to use Conan in your project and just want to install the **mp-units**
library on your file system and use `find_package(mp-units)` from another repository
to find it, it is enough to perform the following steps:
```shell
conan install . -pr <your_conan_profile> -s compiler.cppstd=20 -b=missing
mv CMakeUserPresets.json src
cd src
cmake --preset conan-default -DCMAKE_INSTALL_PREFIX=<your_installation_path>
cmake --build --preset conan-release --target install
```
## Contributing (or just building all the tests and examples)
In case you would like to build all the **mp-units** source code (with unit tests and examples),
you should:
1. Use the _CMakeLists.txt_ from the top-level directory.
2. Run Conan with [`user.build:all`](#user-build-all) = `True`.
```shell
git clone https://github.com/mpusz/mp-units.git && cd units
conan build . -pr <your_conan_profile> -s compiler.cppstd=20 -c user.build:all=True -b missing
```
The above will download and install all of the dependencies needed for the development of the library,
build all of the source code, and run unit tests.
If you prefer to build the project via CMake rather than Conan, then you should replace
the `conan build` with `conan install` command and then follow with a regular CMake build:
```shell
cmake --preset conan-default
cmake --build --preset conan-release
cmake --build --preset conan-release --target test
```
## Building documentation
Starting from **mp-units 2.0** we are using [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/)
to build our documentation. The easiest way to install all the required dependencies
is with `pip`:
```shell
pip install -U mkdocs-material
```
After that, you can either:
- easily [start a live server to preview the documentation as you write](https://squidfunk.github.io/mkdocs-material/creating-your-site/#previewing-as-you-write)
```shell
mkdocs serve
```
- [build the documentation](https://squidfunk.github.io/mkdocs-material/creating-your-site/#building-your-site)
```shell
mkdocs build
```
## Packaging
To test CMake installation and Conan packaging or create a Conan package run:
```shell
conan create . <username>/<channel> -pr <your_conan_profile> -s compiler.cppstd=20 -c user.build:all=True -b missing
```
The above will create a Conan package and run tests provided in _./test_package_ directory.
## Uploading **mp-units** Package to the Conan Server
```shell
conan upload -r <remote-name> --all mp-units/2.0.0@<user>/<channel>
```

View File

@ -0,0 +1,50 @@
# Introduction
**mp-units** is a Modern C++ library that provides compile-time dimensional analysis and unit/quantity
manipulation. The initial versions of the library were inspired by the
[`std::chrono::duration`](https://en.cppreference.com/w/cpp/chrono/duration)
but with each release, the interfaces diverged from the original to provide a better user
experience.
## Open Source
**mp-units** is Free and Open Source, with a permissive
[MIT license](https://github.com/mpusz/mp-units/blob/master/LICENSE.md). Check out the source
code and issue tracking (for questions and support, reporting bugs, suggesting feature requests
and improvements) at <https://github.com/mpusz/mp-units>.
## With the User's Experience in Mind
Most of the critical design decisions in the library are dictated by the requirement of
providing the best user experience possible. Other C++ physical units libraries are
"famous" for their enormous and hard-to-understand error messages (one line of the error log often
do not fit on one slide). The ultimate goal of **mp-units** is to improve this and make compile-time
errors and debugging as easy and user-friendly as possible.
To achieve this goal, several techniques are applied:
- usage of C++20 concepts,
- using strong types for framework entities (instead of type aliases),
- usage of expression templates to improve the readability of generated types,
- limiting the number of template arguments to the bare minimum.
!!! note
In many generic C++ libraries compile-time errors do not happen often. It is hard to
break `std::string` or `std::vector` in a way it won't compile with a huge error
log. Physical Units libraries are different. **Generation of compile-time errors
is the main reason to use such a library.**
## Key Features
| Feature | Description |
|------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **Safety** | - The affine space strong types (`quantity` and `quantity_point`)<br>- Compile-time checked conversions of quantities and units<br>- Unique support for many quantities of the same kind<br>- Type-safe equations on scalar, vector, and tensor quantities and their units<br>- Value-preserving conversions |
| **Performance** | - All the compile-time logic implemented as immediate (`consteval`) functions<br>- As fast or even faster than working with fundamental types<br>- No space size overhead needed to implement high-level abstractions |
| **Great User Experience** | - Optimized for readable compilation errors and great debugging experience<br>- Efficient and composable way to specify a unit of choice<br>- Value-based dimension, unit, and quantity equations |
| **Feature Rich** | - Systems of Quantities<br>- Systems of Units<br>- Scalar, vector, and tensor quantities<br>- The affine space<br>- [Natural units systems](https://en.wikipedia.org/wiki/Natural_units) support<br>- Strong angular system<br>- Supports any unit's magnitude (huge, small, floating-point)<br>- Faster-than-lightspeed constants<br>- Highly adjustable text-output formatting |
| **Easy to Extend** | - Each entity can be defined with a single line of code<br>- User can easily extend the systems with custom dimensions, quantities, and units |
| **Low Standardization Cost** | - Small number of predefined entities needed thanks to composability<br>- No external dependencies (assuming full C++20 support)<br>- No macros in the user interface (besides portability and standard-compliance issues)<br>- Possibility to be standardized as a [freestanding](https://en.cppreference.com/w/cpp/freestanding) part of the C++ Standard Library |

View File

@ -0,0 +1,76 @@
# Quick Start
A **quantity** is a concrete amount of a unit for a quantity type of a specified dimension with a
specific representation, and is represented in the library with a `quantity` class template.
## Creating a quantity
The quantity is created by multiplying a number with a predefined unit:
```cpp
#include <mp-units/systems/si/si.h>
using namespace mp_units;
auto q = 42 * si::metre;
```
!!! note
The above spelling of `metre` is not a typo. For motivation, please check our
[FAQ](../faq/#why-do-we-spell-metre-instead-of-meter).
The above creates an instance of `quantity<si::metre(), int>`. The same can be obtained using
an optional unit symbol:
```cpp
#include <mp-units/systems/si/si.h>
using namespace mp_units;
using namespace mp_units::si::unit_symbols;
auto q = 42 * m;
```
!!! note
Unit symbols introduce a lot of short identifiers into the current namespace, and that is
why they are opt-in. A user has to explicitly "import" them from a dedicated `unit_symbols`
namespace.
## User-provided unit wrappers
Sometimes it might be awkward to type some derived units:
```cpp
auto speed = 60 * (km / h);
```
!!! note
Please note that `60 * km / h` will not compile. To read more about the rationale for such
a design please check our [FAQ](../faq/#why-dont-we-use-udls-to-create-a-quantity).
In case such a unit is used a lot in the project, a user can easily provide a nicely named
wrapper for it with:
```cpp
constexpr auto kmph = km / h;
auto speed = 60 * kmph;
```
or even:
```cpp
constexpr auto kilometre = si::kilo<si::metre>;
constexpr auto kilometre_per_hour = kilometre / si::hour;
constexpr auto kmph = kilometre_per_hour;
auto speed = 60 * kmph;
```
!!! note
In case you wonder why this library does not use UDLs to create quantities, please check
our [FAQ](../faq/#why-dont-we-use-udls-to-create-quantities).

View File

@ -1,222 +0,0 @@
.. default-role:: term
Glossary
========
ISO 80000 [1]_ definitions
--------------------------
.. glossary::
quantity
- Property of a phenomenon, body, or substance, where the property has a magnitude that can
be expressed by means of a number and a reference.
- A reference can be a measurement unit, a measurement procedure, a reference material, or
a combination of such.
- A quantity as defined here is a scalar. However, a vector or a tensor, the components of
which are quantities, is also considered to be a quantity.
- The concept quantity may be generically divided into, e.g. physical quantity,
chemical quantity, and biological quantity, or base quantity and derived quantity.
- Examples of quantities are: mass, length, density, magnetic field strength, etc.
kind of quantity
kind
- Aspect common to mutually comparable `quantities <quantity>`.
- The division of the concept quantity into several kinds is to some extent arbitrary
- i.e. the quantities diameter, circumference, and wavelength are generally considered
to be quantities of the same kind, namely, of the kind of quantity called length.
- Quantities of the same kind within a given `system of quantities` have the same quantity
`dimension`. However, `quantities <quantity>` of the same `dimension` are not necessarily
of the same kind.
- For example, the absorbed dose and the dose equivalent have the same `dimension`.
However, the former measures the absolute amount of radiation one receives whereas
the latter is a weighted measurement taking into account the kind of radiation
on was exposed to.
system of quantities
system
- Set of `quantities <quantity>` together with a set of non-contradictory equations
relating those `quantities <quantity>`.
- Examples of systems of quantities are: the International System of Quantities,
the Imperial System, etc.
base quantity
- `Quantity <quantity>` in a conventionally chosen subset of a given `system of quantities`,
where no `quantity` in the subset can be expressed in terms of the other
`quantities <quantity>` within that subset.
- Base quantities are referred to as being mutually independent since a base quantity
cannot be expressed as a product of powers of the other base quantities.
derived quantity
- `Quantity <quantity>`, in a `system of quantities`, defined in terms of the base
quantities of that system.
International System of Quantities
ISQ
- `System of quantities <system of quantities>` based on the seven
`base quantities <base quantity>`: length, mass, time, electric current, thermodynamic
temperature, amount of substance, and luminous intensity.
- The International System of Units (SI) is based on the ISQ.
dimension of a quantity
quantity dimension
dimension
- Expression of the dependence of a `quantity` on the `base quantities <base quantity>`
of a `system of quantities` as a product of powers of factors corresponding to the
`base quantities <base quantity>`, omitting any numerical factors.
- A power of a factor is the factor raised to an exponent. Each factor is the dimension
of a `base quantity`.
- In deriving the dimension of a quantity, no account is taken of its scalar, vector, or
tensor character.
- In a given `system of quantities`:
- `quantities <quantity>` of the same `kind` have the same quantity dimension,
- `quantities <quantity>` of different quantity dimensions are always of different `kinds <kind>`,
- `quantities <quantity>` having the same quantity dimension are not necessarily of the same `kind`.
quantity of dimension one
dimensionless quantity
- `quantity` for which all the exponents of the factors corresponding to the
`base quantities <base quantity>` in its `quantity dimension` are zero.
- The term “dimensionless quantity” is commonly used and is kept here for historical
reasons. It stems from the fact that all exponents are zero in the symbolic
representation of the `dimension` for such `quantities <quantity>`. The term “quantity
of dimension one” reflects the convention in which the symbolic representation of the
`dimension` for such `quantities <quantity>` is the symbol ``1``. This `dimension` is
not a number, but the neutral element for multiplication of `dimensions <dimension>`.
- The `measurement units <measurement unit>` and values of quantities of dimension one
are numbers, but such `quantities <quantity>` convey more information than a number.
- Some quantities of dimension one are defined as the ratios of two
`quantities of the same kind <kind>`. The `coherent derived unit` is the number one,
symbol ``1``.
- Numbers of entities are quantities of dimension one.
unit of measurement
measurement unit
unit
- Real scalar `quantity`, defined and adopted by convention, with which any other
`quantity of the same kind <kind>` can be compared to express the ratio of the
second `quantity` to the first one as a number.
- Measurement units are designated by conventionally assigned names and symbols.
- Measurement units of `quantities <quantity>` of the same `quantity dimension` may
be designated by the same name and symbol even when the `quantities <quantity>` are
not of the same `kind`.
For example, joule per kelvin and J/K are respectively the name and symbol of both a
measurement unit of heat capacity and a measurement unit of entropy, which are generally
not considered to be `quantities of the same kind <kind>`. However, in some cases special
measurement unit names are restricted to be used with `quantities <quantity>` of specific
`kind` only. For example, the measurement unit second to the power minus one (``1/s``) is
called hertz (``Hz``) when used for frequencies and becquerel (``Bq``) when used for
activities of radionuclides. As another example, the joule (``J``) is used as a unit of
energy, but never as a unit of moment of force, i.e. the newton metre (``N · m``).
- Measurement units of `quantities of dimension one <quantity of dimension one>` are
numbers. In some cases, these measurement units are given special names, e.g. radian,
steradian, and decibel, or are expressed by quotients such as millimole per mole equal
to :math:`10^{3}` and microgram per kilogram equal to :math:`10^{9}`.
base unit
- Measurement unit that is adopted by convention for a `base quantity`.
- In each `coherent system of units`, there is only one base unit for each `base quantity`.
- A base unit may also serve for a `derived quantity` of the same `quantity dimension`.
- For example, the `ISQ` has the base units of: metre, kilogram, second, Ampere, Kelvin, mole,
and candela.
derived unit
- Measurement unit for a `derived quantity`.
- For example, in the `ISQ` Newton, Pascal, and katal are derived units.
coherent derived unit
- `Derived unit <derived unit>` that, for a given `system of quantities` and for a chosen
set of `base units <base unit>`, is a product of powers of `base units <base unit>` with
no other proportionality factor than one.
- A power of a `base unit` is the `base unit` raised to an exponent.
- Coherence can be determined only with respect to a particular `system of quantities`
and a given set of `base units <base unit>`. That is, if the metre and the second are
base units, the metre per second is the coherent derived unit of speed.
system of units
- Set of `base units <base unit>` and `derived units <derived unit>`, together with
their multiples and submultiples, defined in accordance with given rules, for a given
`system of quantities`.
coherent system of units
- `System of units <system of units>`, based on a given `system of quantities`, in which
the measurement unit for each `derived quantity` is a `coherent derived unit`.
- A `system of units` can be coherent only with respect to a `system of quantities` and
the adopted `base units <base unit>`.
off-system measurement unit
off-system unit
- `Measurement unit <measurement unit>` that does not belong to a given `system of units`.
For example, the electronvolt (:math:`≈ 1,602 18 × 10^{19} J`) is an off-system measurement
unit of energy with respect to the `SI` or day, hour, minute are off-system measurement
units of time with respect to the `SI`.
International System of Units
SI
- `System of units <system of units>`, based on the `International System of Quantities`,
their names and symbols, including a series of prefixes and their names and symbols,
together with rules for their use, adopted by the General Conference on Weights and
Measures (CGPM)
quantity value
value of a quantity
value
- Number and reference together expressing magnitude of a `quantity`.
- The number can be complex.
- A quantity value can be presented in more than one way.
- In the case of vector or tensor quantities, each component has a quantity value.
- For example, force acting on a given particle, e.g. in Cartesian components
:math:`(F_x; F_y; F_z) = (31,5; 43,2; 17,0) N`, where
:math:`(31,5; 43,2; 17,0)` is a numerical-value vector and :math:`N` (newton)
is the unit, or :math:`(F_x; F_y; F_z) = (31,5 N; 43,2 N; 17,0 N)`
where each component is a quantity.
Other definitions
-----------------
.. glossary::
:sorted:
base dimension
- A `dimension` of a `base quantity`.
derived dimension
- A `dimension` of a `derived quantity`.
- Often implemented as a list of exponents of `base dimensions <base dimension>`.
normalized derived dimension
A `derived dimension` in which:
- `base dimensions <base dimension>` are not repeated in a list (each base dimension is provided at most once),
- `base dimensions <base dimension>` are consistently ordered,
- `base dimensions <base dimension>` having zero exponent are elided.
derived dimension recipe
recipe
- The ordered list of exponents used to define a derived dimension
- The list may contain both base and derived dimensions (in the latter case
the dimension is being extracted to base dimensions by the framework)
- The order and types of dimensions used in the recipe determine how an unnamed
dimension's unit symbol is being printed in the text output
scalable number
- Not a `quantity`
- Can be passed as a representation type to the :class:`units::quantity` type or be used as a factor
while multiplying or dividing a `quantity`.
.. rubric:: Footnotes:
.. [1] [ISO80000]_ gives general information and definitions concerning quantities, systems of quantities,
units, quantity and unit symbols, and coherent unit systems, especially the International System
of Quantities, ISQ, and the International System of Units, SI. The principles laid down in
ISO 80000-1:2009 are intended for general use within the various fields of science and technology
and as an introduction to other parts of the Quantities and units series. Ordinal quantities and
nominal properties are outside the scope of ISO 80000-1:2009.

32
docs/index.md Normal file
View File

@ -0,0 +1,32 @@
# Welcome to **mp-units**!
**mp-units** is a compile-time enabled feature-rich Modern C++ header-only library that provides
compile-time dimensional analysis and unit/quantity manipulation. Its key strengths include safety,
performance, and developer experience.
The library source code is hosted on [GitHub](https://github.com/mpusz/mp-units) with a permissive
[MIT license](https://github.com/mpusz/units/blob/master/LICENSE.md).
!!! info "Help needed!"
The **mp-units** library might be the subject of ISO standardization for C++29. More on this can
be found in the ISO C++ proposal [P1935](https://wg21.link/p1935). We are actively looking for
parties interested in field-trialing the library.
??? info "Supported compilers"
This library tries to provide the best user experience possible with the C++ language.
To achieve that, it extensively uses C++20 features and the
[explicit object parameter](https://en.cppreference.com/w/cpp/language/member_functions#Explicit_object_parameter)
from C++23.
Even though the library benefits from C++23 (if available), C++20 is enough to compile and
use all of the library's functionality. C++23 features are hidden behind a preprocessor macro
providing a backward-compatible way to use it.
Sadly, as of today, only a few compilers provide full C++20 support. The library compiles fine
on the following compilers (or newer):
- gcc-12.2
In the upcoming weeks, we will be actively working to extend the support to other compilers as well.

View File

@ -1,62 +0,0 @@
Welcome to mp-units!
====================
**mp-units** is a compile-time enabled Modern C++ library that provides compile-time dimensional
analysis and unit/quantity manipulation. Source code is hosted on `GitHub <https://github.com/mpusz/units>`_
with a permissive `MIT license <https://github.com/mpusz/units/blob/master/LICENSE.md>`_.
.. important::
The **mp-units** library is the subject of ISO standardization for C++23/26. More on this can
be found in ISO C++ paper `P1935 <https://wg21.link/p1935>`_ and
`NDC TechTown 2021 talk <https://www.youtube.com/watch?v=nudq58d0TFc>`_. We are actively looking for
parties interested in field trialing the library.
.. note::
This library targets C++23/26 and extensively uses C++20 features. This is why it requires the latest C++
compilers. The following compilers (or newer) are supported:
- gcc-10
- clang-12
- Visual Studio 16.9
- Apple clang 13
.. toctree::
:maxdepth: 2
:caption: Getting Started:
introduction
quick_start
framework
defining_systems
use_cases
design
examples
usage
faq
.. toctree::
:maxdepth: 2
:caption: Reference:
reference/core
reference/systems
reference/math
reference/random
.. note::
Source code documentation tools used to generate the above chapter still do not understand
C++20 to well which results in some issues in the generated output. We do our best to address
this ASAP.
.. toctree::
:maxdepth: 1
:caption: Appendix:
glossary
genindex
CHANGELOG
references

View File

@ -1,71 +0,0 @@
Introduction
============
**mp-units** is a compile-time enabled Modern C++ library that provides compile-time
dimensional analysis and unit/quantity manipulation. The basic idea and design
heavily bases on `std::chrono::duration <https://en.cppreference.com/w/cpp/chrono/duration>`_
and extends it to work properly with many dimensions.
Thanks to compile-time operations no runtime execution cost is introduced,
facilitating the use of this library to provide dimension checking in
performance-critical code. Support for quantities and units for arbitrary unit
system models and arbitrary value types is provided, as is a fine-grained
general facility for unit conversions.
The library architecture has been designed with flexibility and extensibility
in mind. The demonstrations of the ease of adding new dimensions, their units,
and unit conversions are provided in the :ref:`examples:Examples`.
Open Source
-----------
**mp-units** is Free and Open Source, with a permissive
`MIT license <https://github.com/mpusz/units/blob/master/LICENSE.md>`_. Check
out the source code and issue tracking (for questions and support, reporting
bugs and suggesting feature requests and improvements) at https://github.com/mpusz/units.
Approach
--------
1. Safety and performance
- strong types
- compile-time safety
- ``constexpr`` all the things
- as fast or even faster than when working with fundamental types
2. The best possible user experience
- compiler errors
- debugging
3. No macros in the user interface
4. Easy extensibility
5. No external dependencies
6. Possibility to be standardized as a freestanding part of the C++ Standard
Library
With the User's Experience in Mind
----------------------------------
Most of the important design decisions in the library are dictated by the requirement of
providing the best user experience as possible. Other C++ physical units libraries are
"famous" for their huge error messages (one line of the error log often do not fit on one
slide). The ultimate goal of **mp-units** is to improve this and make compile-time errors
and debugging as easy and user-friendly as possible.
To achieve this goal several techniques are applied:
- usage of C++20 concepts,
- using strong types for framework entities (instead of type aliases),
- limiting the number of template arguments to the bare minimum,
- :ref:`design/downcasting:The Downcasting Facility`.
.. important::
In many generic C++ libraries compile-time errors do not happen often. It is hard to
break ``std::string`` or ``std::vector`` in a way it won't compile with a huge error
log. Physical Units libraries are different. **Generation of compile-time errors
is the main reason to create such a library.**

View File

@ -0,0 +1,7 @@
# Core Library
## Concepts
## Expression templates
## Dimensions

View File

@ -1,88 +0,0 @@
Quick Start
===========
Here is a small example of possible operations::
#include <units/isq/si/area.h>
#include <units/isq/si/frequency.h>
#include <units/isq/si/length.h>
#include <units/isq/si/speed.h>
#include <units/isq/si/time.h>
using namespace units::isq::si::references;
// simple numeric operations
static_assert(10 * km / 2 == 5 * km);
// unit conversions
static_assert(1 * h == 3600 * s);
static_assert(1 * km + 1 * m == 1001 * m);
// dimension conversions
inline constexpr auto kmph = km / h;
static_assert(1 * km / (1 * s) == 1000 * (m / s));
static_assert(2 * kmph * (2 * h) == 4 * km);
static_assert(2 * km / (2 * kmph) == 1 * h);
static_assert(2 * m * (3 * m) == 6 * m2);
static_assert(10 * km / (5 * km) == 2);
static_assert(1000 / (1 * s) == 1 * kHz);
.. admonition:: Try it on Compiler Explorer
`Example #1 <https://godbolt.org/z/qbbbnfK3s>`_
This library requires some C++20 features (concepts, classes as
:abbr:`NTTP (Non-Type Template Parameter)`, ...). Thanks to them the user gets a powerful
but still easy to use interface where all unit conversions and dimensional analysis can be
performed without sacrificing on accuracy. Please see the below example for a quick preview
of basic library features::
#include <units/format.h>
#include <units/isq/si/international/length.h>
#include <units/isq/si/international/speed.h>
#include <units/isq/si/length.h>
#include <units/isq/si/speed.h>
#include <units/isq/si/time.h>
#include <units/quantity_io.h>
#include <iostream>
using namespace units::isq;
constexpr Speed auto avg_speed(Length auto d, Time auto t)
{
return d / t;
}
int main()
{
using namespace units::isq::si::literals;
using namespace units::isq::si::references;
using namespace units::aliases::isq::si::international;
constexpr Speed auto v1 = 110 * (km / h);
constexpr Speed auto v2 = mi_per_h(70.);
constexpr Speed auto v3 = avg_speed(220_q_km, 2_q_h);
constexpr Speed auto v4 = avg_speed(si::length<si::international::mile>(140), si::time<si::hour>(2));
constexpr Speed auto v5 = quantity_cast<si::speed<si::metre_per_second>>(v3);
constexpr Speed auto v6 = quantity_cast<si::metre_per_second>(v4);
constexpr Speed auto v7 = quantity_cast<int>(v6);
std::cout << v1 << '\n'; // 110 km/h
std::cout << v2 << '\n'; // 70 mi/h
std::cout << std::format("{}", v3) << '\n'; // 110 km/h
std::cout << std::format("{:*^14}", v4) << '\n'; // ***70 mi/h****
std::cout << std::format("{:%Q in %q}", v5) << '\n'; // 30.5556 in m/s
std::cout << std::format("{0:%Q} in {0:%q}", v6) << '\n'; // 31.2928 in m/s
std::cout << std::format("{:%Q}", v7) << '\n'; // 31
}
.. admonition:: Try it on Compiler Explorer
`Example #2 <https://godbolt.org/z/b4a3Ya6dY>`_
.. seealso::
You can find more code examples in the :ref:`examples:Examples` chapter.

View File

@ -1,12 +0,0 @@
Core Library
============
.. toctree::
:maxdepth: 1
core/concepts
core/types
core/functions
core/metafunctions
core/customization_points
core/downcasting

View File

@ -1,169 +0,0 @@
.. namespace:: units
Concepts
========
.. note::
All names defined in this chapter reside in the :any:`units` namespace unless
specified otherwise.
.. concept:: template<typename T> Prefix
A concept matching a symbol prefix. Satisfied by all instantiations of :struct:`prefix`.
.. concept:: template<ratio R> UnitRatio
Satisfied by all ratio values for which :expr:`R.num > 0` and :expr:`R.den > 0`.
.. concept:: template<typename T> BaseDimension
A concept matching all base dimensions in the library. Satisfied by all dimension types
derived from the instantiation of :class:`base_dimension`.
.. concept:: template<typename T> Exponent
A concept matching dimension's exponents. Satisfied by all instantiations of :class:`exponent`.
.. concept:: template<typename T> DerivedDimension
A concept matching all derived dimensions in the library. Satisfied by all dimension
types derived from the instantiation of ``detail::derived_dimension_base``.
.. concept:: template<typename T> Dimension
A concept matching all dimensions in the library. Satisfied by all dimension types for
which either :expr:`BaseDimension<T>` or :expr:`DerivedDimension<T>` is ``true``.
.. concept:: template<typename T> Unit
A concept matching all unit types in the library. Satisfied by all unit types derived
from the instantiation of :class:`scaled_unit`.
.. concept:: template<typename T> NamedUnit
A concept matching all unit types that have an atomic text symbol that can be used to aggregate it with
other named units to form a final symbol of a derived unit.
.. concept:: template<typename T> AliasUnit
A concept matching all alias unit types in the library. Satisfied by all unit types derived
from the instantiation of :class:`alias_unit`.
.. concept:: template<typename U, typename D> UnitOf
A concept matching only units of a specified dimension. Satisfied by all unit types that
satisfy :expr:`Unit<U>`, :expr:`Dimension<D>`, and for which :expr:`U::reference` and
``dimension_unit<D>::reference`` denote the same unit type.
:tparam U: Type to verify against concept constraints.
:tparam D: Dimension type to use for verification.
.. concept:: template<typename T> Quantity
A concept matching all quantities in the library. Satisfied by all instantiations of :class:`quantity`.
.. concept:: template<typename T> QuantityLike
A concept matching all quantity-like types other than specialization of :class:`quantity`. Satisfied by
all types for which a correct specialization of :class:`quantity_like_traits` type trait is provided.
.. concept:: template<typename T> QuantityPointLike
A concept matching all quantity-point-like types other than specialization of :class:`quantity_point`.
Satisfied by all types for which a correct specialization of :class:`quantity_point_like_traits` type trait is provided.
.. concept:: template<typename T> WrappedQuantity
A concept matching types that wrap quantity objects. Satisfied by all wrapper types that
satisfy :expr:`Quantity<typename T::value_type> || QuantityLike<typename T::value_type>` recursively
(i.e. ``std::optional<si::length<si::metre>>``).
.. concept:: template<typename T> Representation
A concept matching types that can be used as a `Quantity` representation type. Satisfied
by types that match ``(!Quantity<T>) && (!QuantityLike<T>) && (!WrappedQuantity<T>) && std::regular<T>``
and satisfy one of the following:
- if ``common_type_with<T, std::intmax_t>`` is ``true``, then ``std::common_type_t<T, std::intmax_t>``
must at least provide binary multiplication and division operators,
- otherwise, ``T::value_type`` must be valid, ``common_type_with<T::value_type, std::intmax_t>`` be
``true``, and ``std::common_type_t<T::value_type, std::intmax_t>`` must at least provide binary
multiplication and division operators with itself and ``T``.
.. concept:: template<typename T> QuantityPoint
A concept matching all quantity points in the library. Satisfied by all instantiations of
:class:`quantity_point`.
.. concept:: template<typename T> Kind
A concept matching all kind types. Satisfied by all kind types derived from an specialization of
:class:`kind`.
.. concept:: template<typename T> PointKind
A concept matching all point kind types. Satisfied by all point kind types derived from an specialization of
:class:`point_kind`.
.. concept:: template<typename T> QuantityKind
A concept matching all quantity kinds in the library. Satisfied by all specializations of
:class:`quantity_kind`.
.. concept:: template<typename T> QuantityPointKind
A concept matching all quantity point kinds in the library. Satisfied by all specializations of
:class:`quantity_point_kind`.
.. concept:: template<typename Dim, template<typename...> typename DimTemplate> DimensionOfT
A concept matching all dimensions being the instantiations derived from the provided dimension
class template.
.. concept:: template<typename Q, template<typename...> typename DimTemplate> QuantityOfT
A concept matching all quantities with a dimension being the instantiation derived from
the provided dimension class template.
.. concept:: template<typename Q, typename Dim> QuantityOf
A concept matching all quantities with a dimension being the instantiation derived from
the provided dimension type.
.. concept:: template<typename Q1, typename Q2> QuantityEquivalentTo
A concept matching two equivalent quantities. Satisfied by quantities having equivalent dimensions.
.. concept:: template<typename QP, typename Dim> QuantityPointOf
A concept matching all quantity points with a dimension being the instantiation derived from
the provided dimension type.
.. concept:: template<typename QP1, typename QP2> QuantityPointEquivalentTo
A concept matching two equivalent quantity points. Satisfied by quantity points having equivalent
dimensions.
.. concept:: template<typename QK, typename K> QuantityKindOf
A concept matching only quantity kinds of a specific kind.
:tparam QK: Quantity kind to verify.
:tparam K: Kind type to use for verification.
.. concept:: template<typename QK1, typename QK2> QuantityKindEquivalentTo
A concept matching two equivalent quantity kinds. Satisfied by quantity kinds having equivalent kinds.
.. concept:: template<typename QPK, typename PK> QuantityPointKindOf
A concept matching only quantity point kinds of a specific point kind.
:tparam QPK: Quantity point kind to verify.
:tparam PK: Point kind type to use for verification.
.. concept:: template<typename QPK1, typename QPK2> QuantityPointKindEquivalentTo
A concept matching two equivalent quantity point kinds. Satisfied by quantity point kinds having
equivalent kinds.

View File

@ -1,13 +0,0 @@
Customization Points
====================
.. doxygenvariable:: units::treat_as_floating_point
.. doxygenstruct:: units::quantity_values
:members:
.. doxygenstruct:: units::quantity_like_traits
:members:
.. doxygenstruct:: units::quantity_point_like_traits
:members:

View File

@ -1,20 +0,0 @@
The Downcasting Facility
========================
.. doxygenenum:: downcast_mode
.. concept:: template<typename T> Downcastable
.. doxygenstruct:: units::downcast_base
:members:
.. doxygenstruct:: units::downcast_child
:members:
.. doxygenstruct:: units::downcast_poison
:members:
.. doxygenstruct:: units::downcast_dispatch
:members:
.. doxygentypedef:: units::downcast

View File

@ -1,4 +0,0 @@
Metafunctions
=============
.. doxygentypedef:: dimension_unit

View File

@ -1,16 +0,0 @@
Types
=====
.. toctree::
:maxdepth: 1
types/quantity
types/quantity_point
types/kinds
types/quantity_kind
types/quantity_point_kind
types/dimensions
types/units
types/prefixes
types/reference
types/utilities

View File

@ -1,11 +0,0 @@
Dimensions
==========
.. doxygenstruct:: units::base_dimension
:members:
.. doxygenstruct:: units::exponent
:members:
.. doxygenstruct:: units::derived_dimension
:members:

View File

@ -1,8 +0,0 @@
Kinds
=====
.. doxygenstruct:: units::kind
:members:
.. doxygenstruct:: units::point_kind
:members:

View File

@ -1,5 +0,0 @@
Prefixes
========
.. doxygenstruct:: units::prefix
:members:

View File

@ -1,6 +0,0 @@
Quantity
========
.. doxygenclass:: units::quantity
:members:
:undoc-members:

View File

@ -1,6 +0,0 @@
Quantity Kind
=============
.. doxygenclass:: units::quantity_kind
:members:
:undoc-members:

View File

@ -1,6 +0,0 @@
Quantity Point
==============
.. doxygenclass:: units::quantity_point
:members:
:undoc-members:

View File

@ -1,6 +0,0 @@
Quantity Point Kind
===================
.. doxygenclass:: units::quantity_point_kind
:members:
:undoc-members:

View File

@ -1,6 +0,0 @@
Quantity Reference
==================
.. doxygenstruct:: units::reference
:members:
:undoc-members:

View File

@ -1,26 +0,0 @@
Units
=====
.. doxygenstruct:: units::scaled_unit
:members:
.. doxygenstruct:: units::named_unit
:members:
.. doxygenstruct:: units::named_scaled_unit
:members:
.. doxygenstruct:: units::prefixed_unit
:members:
.. doxygenstruct:: units::derived_unit
:members:
.. doxygenstruct:: units::derived_scaled_unit
:members:
.. doxygenstruct:: units::alias_unit
:members:
.. doxygenstruct:: units::prefixed_alias_unit
:members:

View File

@ -1,9 +0,0 @@
Utilities
=========
.. toctree::
:maxdepth: 1
utilities/ratio
utilities/basic_symbol_text
utilities/basic_fixed_string

Some files were not shown because too many files have changed in this diff Show More