Sphinx-based documentation added

This commit is contained in:
Mateusz Pusz
2020-03-09 18:55:41 +01:00
parent af6358fbdb
commit b65328d575
88 changed files with 6476 additions and 154 deletions

View File

@ -19,5 +19,6 @@ if [[ "$(uname -s)" == 'Darwin' ]]; then
pyenv activate conan
fi
pip install -r docs/requirements.txt
pip install -U conan_package_tools
conan user

View File

@ -1,6 +1,6 @@
# Release notes
- 0.5.0 ???
- 0.5.0 WIP
- 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)
@ -9,12 +9,17 @@
- Added official CGS system support
- Added official data information system support
- Repository file tree cleanup
- `ratio` refactored to contain `Exp` template parameter
- `ratio` refactored to contain `Exp` template parameter (thanks a lot @oschonrock!)
- SI fundamental constants added
- `q_` prefix applied to all the UDLs
- `q_` prefix applied to all the UDLs (thanks @kwikius)
- `unknown_unit` renamed to `unknown_coherent_unit`
- Project documentation extended and switched to Sphinx
- A few more usage examples added
- ...
Many thanks to GitHub users @oschonrock and @kwikius 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

View File

@ -48,3 +48,6 @@ add_subdirectory(test)
# add usage example
add_subdirectory(example)
# generate project documentation
add_subdirectory(docs)

198
README.md
View File

@ -8,10 +8,35 @@
## TL;DR
This library is the subject of this ISO C++ proposal: [P1935](https://wg21.link/p1935). It is
explained in this [CppCon 2019 talk](https://youtu.be/0YW6yxkdhlU) (slightly dated see below).
We are working towards potentially having it standardized for C++23 and are actively looking
for parties interested in field trialing the library.
`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` and extends it to work properly with many dimensions.
Here is a small example of possible operations:
```cpp
// simple numeric operations
static_assert(10q_km / 2 == 5q_km);
// unit conversions
static_assert(1q_h == 3600q_s);
static_assert(1q_km + 1q_m == 1001q_m);
// dimension conversions
static_assert(2q_m * 3q_m == 6q_m2);
static_assert(10q_km / 5q_km == 2);
static_assert(1000 / 1q_s == 1q_kHz);
static_assert(1q_km / 1q_s == 1000q_mps);
static_assert(2q_kmph * 2q_h == 4q_km);
static_assert(2q_km / 2q_kmph == 1q_h);
```
_Try it on the [Compiler Explorer](???)._
This library requires some C++20 features (concepts, classes as NTTPs, ...). Thanks to
them the user gets a powerful but still easy to use interface and 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:
```cpp
#include <units/physical/si/velocity.h>
@ -40,156 +65,29 @@ int main()
}
```
Try it on [Compiler Explorer](https://godbolt.org/z/_Yx6D7).
_Try it on the [Compiler Explorer](https://godbolt.org/z/_Yx6D7)._
**The mp-units library is the subject of this ISO C++ paper: [P1935](https://wg21.link/p1935).
It is explained in this [CppCon 2019 talk](https://youtu.be/0YW6yxkdhlU) (slightly dated now).
We are working towards potentially having it standardized for C++23 and are actively looking
for parties interested in field trialing the library.**
## Summary
`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` and extends it to work properly with many dimensions.
Here is a small example of possible operations:
```cpp
// simple numeric operations
static_assert(10q_km / 2 == 5q_km);
// unit conversions
static_assert(1q_h == 3600q_s);
static_assert(1q_km + 1q_m == 1001q_m);
// dimension conversions
static_assert(1q_km / 1q_s == 1000q_mps);
static_assert(2q_kmph * 2q_h == 4q_km);
static_assert(2q_km / 2q_kmph == 1q_h);
static_assert(1000 / 1q_s == 1q_kHz);
static_assert(10q_km / 5q_km == 2);
```
## Getting Started
The library framework consists of a few concepts: quantities, units, dimensions and their
exponents. From the user's point of view the most important is a `quantity`.
A quantity is a concrete amount of a unit for a specified dimension with a specific representation:
```cpp
units::quantity<units::si::dim_length, units::si::kilometre, double> d(123);
```
To simplify quantity creation the library provides helper aliases for quantities of different
dimensions. Thanks to then the above example can be rewritten as follows:
```cpp
units::si::length<units::si::kilometre, double> d(123);
```
To simplify creations of compile-time known constants the library provides UDLs for each unit.
Thanks to them the same code can be as simple as:
```cpp
using namespace units::si::literals;
auto d = 123q_km; // units::length<units::si::kilometre, std::int64_t>
```
For brevity, the next examples will assume:
```cpp
using namespace units;
```
Let's assume that the user wants to write the following code:
```cpp
int main()
{
using namespace si::literals;
auto v1 = avg_speed(220q_km, 2q_h);
auto v2 = avg_speed(140q_mi, 2q_h);
// ...
}
```
`avg_speed` is a simple function calculating an average speed from a distance and duration. It can
be implemented as:
```cpp
constexpr si::velocity<si::metre_per_second, int> avg_speed(si::length<si::metre> d, si::time<si::second> t)
{
return d / t;
}
```
However, this function will perform unnecessary intermediate conversions (from kilometers to meters,
from hours to seconds, and from meters per second to kilometers per hour). To eliminate all that
overhead we have to write a template function:
```cpp
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 ensure that the returned type is actually a velocity. However,
it might not always be the case. For more complicated calculations we would like to ensure
that we are returning a correct type and also inform the user of that fact in the function
template interface. Also we might want to implement a truly generic function that will work
efficiently not only with SI units but also with other systems of units like CGS. The solution
to this are C++20 concepts and generic functions.
```cpp
constexpr Velocity auto avg_speed(Length auto d, Time auto t)
{
return d / t;
}
```
The units library also tries really hard to print any quantity in the most user friendly
fashion:
```cpp
int main()
{
using namespace si::literals;
using namespace international::literals;
Velocity auto v1 = avg_speed(220q_km, 2q_h);
Velocity auto v2 = avg_speed(140q_mi, 2q_h);
std::cout << v1 << '\n'; // 110 km/h
std::cout << quantity_cast<si::metre_per_second>(speed) << '\n'; // 30.5556 m/s
std::cout << v2 << '\n'; // 70 mi/h
}
```
## Library design
A detailed `mp-units` library design rationale and documentation can be found in
[doc/DESIGN.md](doc/DESIGN.md)
## Repository structure
This repository contains three independent `cmake`-based projects:
1. `./src` - header-only project containing whole `mp-units` library
2. `.` - project used as an entry point for library development (it wraps `./src` project
together with usage examples and tests)
3. `./test_package` - library installation and Conan package verification
NOTE: Please note that this repository depends on a git submodule in the `./cmake/common`
subdirectory.
## Building, testing, and installation
## Downloading, Building, Testing, and Installation
For a detailed information on project compilation, testing and reuse please refer to
[doc/INSTALL.md](doc/INSTALL.md).
NOTE: This library as of now compiles correctly only with gcc-9.1 and newer.
## User Guide
A detailed `mp-units` library design rationale and documentation can be found in
[doc/DESIGN.md](doc/DESIGN.md)
## Library Design
A detailed `mp-units` library design rationale and documentation can be found in
[doc/DESIGN.md](doc/DESIGN.md)

11
cmake/FindSphinx.cmake Normal file
View File

@ -0,0 +1,11 @@
# 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

@ -63,7 +63,7 @@ class UnitsConan(ConanFile):
def _configure_cmake(self, folder="src"):
cmake = CMake(self)
if self._run_tests:
# developer's mode (unit tests, examples, restrictive compilation warnings, ...)
# developer's mode (unit tests, examples, documentation, restrictive compilation warnings, ...)
cmake.configure()
else:
# consumer's mode (library sources only)
@ -87,6 +87,8 @@ class UnitsConan(ConanFile):
def build_requirements(self):
if self._run_tests:
self.build_requires("Catch2/2.11.0@catchorg/stable")
# TODO update doxygen to the latest version when available
self.build_requires("doxygen_installer/1.8.17@bincrafters/stable")
def build(self):
cmake = self._configure_cmake()

1
docs/CHANGELOG.md Symbolic link
View File

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

104
docs/CMakeLists.txt Normal file
View File

@ -0,0 +1,104 @@
# 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.
find_package(Doxygen REQUIRED)
find_package(Sphinx REQUIRED)
set(DOXYGEN_INPUT_DIR "${PROJECT_SOURCE_DIR}/src")
set(DOXYGEN_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/doxygen")
set(DOXYGEN_INDEX_FILE "${DOXYGEN_OUTPUT_DIR}/xml/index.xml")
set(DOXYFILE_IN "${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in")
set(DOXYFILE_OUT "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile")
# Find all the public headers
file(GLOB_RECURSE UNITS_PUBLIC_HEADERS ${DOXYGEN_INPUT_DIR}/*.h)
# Replace variables inside @@ with the current values
configure_file("${DOXYFILE_IN}" "${DOXYFILE_OUT}" @ONLY)
# Doxygen won't create this for us
file(MAKE_DIRECTORY "${DOXYGEN_OUTPUT_DIR}")
# Only regenerate Doxygen when the Doxyfile or public headers change
add_custom_command(OUTPUT "${DOXYGEN_INDEX_FILE}"
DEPENDS ${UNITS_PUBLIC_HEADERS}
COMMAND "${DOXYGEN_EXECUTABLE}" "${DOXYFILE_OUT}"
MAIN_DEPENDENCY "${DOXYFILE_OUT}" "${DOXYFILE_IN}"
COMMENT "Generating docs:"
VERBATIM)
# Nice named target so we can run the job easily
add_custom_target(doxygen ALL DEPENDS "${DOXYGEN_INDEX_FILE}")
set(SPHINX_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}")
set(SPHINX_BUILD "${CMAKE_CURRENT_BINARY_DIR}/sphinx")
set(SPHINX_INDEX_FILE "${SPHINX_BUILD}/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}" -b html -j auto -Dbreathe_projects.mp-units="${DOXYGEN_OUTPUT_DIR}/xml" "${SPHINX_SOURCE}" "${SPHINX_BUILD}"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/_static/css/custom.css"
"${CMAKE_CURRENT_SOURCE_DIR}/CHANGELOG.md"
"${CMAKE_CURRENT_SOURCE_DIR}/design.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/design/quantity.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/hello_units.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/avg_speed.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/faq.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/framework.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/framework/basic_concepts.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/framework/conversions_and_casting.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/framework/dimensions.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/framework/quantities.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/concepts.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/functions.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/systems.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/types.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/scenarios.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/scenarios/extensions.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/scenarios/legacy_interfaces.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/scenarios/unknown_units_and_dimensions.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/usage.rst"
"${DOXYGEN_INDEX_FILE}"
MAIN_DEPENDENCY "${SPHINX_SOURCE}/conf.py"
COMMENT "Generating documentation with Sphinx")
# Nice named target so we can run the job easily
add_custom_target(sphinx ALL DEPENDS ${SPHINX_INDEX_FILE})
# Add an install target to install the docs
include(GNUInstallDirs)
install(DIRECTORY ${SPHINX_BUILD}
DESTINATION ${CMAKE_INSTALL_DOCDIR})

View File

@ -961,3 +961,5 @@ struct quantity_values;
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.
3. Why do we spell `metre` instead of `meter`?

86
docs/Doxyfile.in Normal file
View File

@ -0,0 +1,86 @@
# 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

View File

@ -1,5 +1,20 @@
# Installation Guide
## Repository structure
This repository contains three independent `cmake`-based projects:
1. `./src`
- header-only project containing whole `mp-units` library
2. `.`
- project used as an entry point for library development (it wraps `./src` project
together with usage examples and tests)
3. `./test_package` - library installation and Conan package verification
NOTE: Please note that this repository depends on a git submodule in the `./cmake/common`
subdirectory.
## Installation and Reuse
There are a few different ways of installing/reusing `units` in your project.

115
docs/README.md Normal file
View File

@ -0,0 +1,115 @@
# `mp-units` - Documentation
## How to build?
1. Install the requirements (Sphinx) with:
```shell
pip3 install -r docs/requirements.txt
```
2. Install all dependencies with Conan for a developer's build:
```shell
conan install .. -pr <your_conan_profile> -s compiler.cppstd=20 -e CONAN_RUN_TESTS=True -b outdated
```
3. Install Python 3
4. Build the documentation with a regular CMake build
## How to contribute?
To make any contribution to **mp-units** documentation please fork this repository and open
a Pull Request.
### Style Guidelines
This guidelines are just general good practices for the formatting and structure of the whole
documentation and do not pretend to be a stopper for any helpful contribution. Any contribution
that may include relevant information for **mp-units** users will always be welcomed.
**mp-units** documentation is written in [reStructuredText](http://docutils.sourceforge.net/rst.html)
and follows [reStructuredText Markup Specification](http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html).
[Quick reStructuredText](http://docutils.sourceforge.net/docs/user/rst/quickref.html) is also
used for reference.
Any detail not covered by this guidelines will follow the aforementioned rules.
#### Section titles
Use section titles in this level of importance:
```rst
Section Title
=============
Subsection Title
----------------
Subsubsection Title
^^^^^^^^^^^^^^^^^^^
```
#### Text emphasis/highlighting
- **Bold text** to highlight important text:
```rst
**mp-units** is a compile-time enabled Modern C++ library that provides compile-time dimensional
analysis and unit/quantity manipulation.
```
- *Italics* to refer to file names, directory names, and paths.
```rst
Create Conan configuration file (either *conanfile.txt* or *conanfile.py*) in your project's
top-level directory...
```
- ``Inline literals`` to refer to the in examples that is not a part of the **mp-units** library:
```rst
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.
```
#### Literal blocks
Most of the C++ code examples should be provided as literal blocks after double `::` symbol:
```rst
For this dimension-specific concepts come handy again and with usage of C++20 generic
functions our function can look as simple as::
constexpr Velocity auto avg_speed(Length auto d, Time auto t)
{
return d / t;
}
```
#### code-blocks
Use code-blocks for exceptional cases like code samples in other languages or a need
to emphasize specific lines of code:
```rst
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 = 2q_m;
Length auto dist2 = 1q_m;
Length auto res1 = dist1 + dist2;
Length auto res2 = dist1 - dist2;
```
#### Indentation and line length
Make sure all indentation is done with spaces. Normally 2 space indentation for bulleted lists
and 4 space indentation for code blocks and RST directives contents:
Do not leave any unnecessary or trailing spaces.

20
docs/_static/css/custom.css vendored Normal file
View File

@ -0,0 +1,20 @@
@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

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

@ -0,0 +1,32 @@
"""
Sphinx Read the Docs theme.
From https://github.com/ryan-roemer/sphinx-bootstrap-theme.
"""
from os import path
import sphinx
__version__ = '0.4.3.dev0'
__version_full__ = __version__
def get_html_theme_path():
"""Return list of HTML theme paths."""
cur_dir = path.abspath(path.dirname(path.dirname(__file__)))
return cur_dir
# See http://www.sphinx-doc.org/en/stable/theming.html#distribute-your-theme-as-a-python-package
def setup(app):
app.add_html_theme('sphinx_rtd_theme', path.abspath(path.dirname(__file__)))
if sphinx.version_info >= (1, 8, 0):
# Add Sphinx message catalog for newer versions of Sphinx
# See http://www.sphinx-doc.org/en/master/extdev/appapi.html#sphinx.application.Sphinx.add_message_catalog
rtd_locale_path = path.join(path.abspath(path.dirname(__file__)), 'locale')
app.add_message_catalog('sphinx', rtd_locale_path)
return {'parallel_read_safe': True, 'parallel_write_safe': True}

View File

@ -0,0 +1,82 @@
{# Support for Sphinx 1.3+ page_source_suffix, but don't break old builds. #}
{% if page_source_suffix %}
{% set suffix = page_source_suffix %}
{% else %}
{% set suffix = source_suffix %}
{% endif %}
{% if meta is defined and meta is not none %}
{% set check_meta = True %}
{% else %}
{% set check_meta = False %}
{% endif %}
{% if check_meta and 'github_url' in meta %}
{% set display_github = True %}
{% endif %}
{% if check_meta and 'bitbucket_url' in meta %}
{% set display_bitbucket = True %}
{% endif %}
{% if check_meta and 'gitlab_url' in meta %}
{% set display_gitlab = True %}
{% endif %}
<div role="navigation" aria-label="breadcrumbs navigation">
<ul class="wy-breadcrumbs">
{% block breadcrumbs %}
<li><a href="{{ pathto(master_doc) }}" class="icon icon-home"></a> &raquo;</li>
{% for doc in parents %}
<li><a href="{{ doc.link|e }}">{{ doc.title }}</a> &raquo;</li>
{% endfor %}
<li>{{ title }}</li>
{% endblock %}
{% block breadcrumbs_aside %}
<li class="wy-breadcrumbs-aside">
{% if hasdoc(pagename) %}
{% if display_github %}
{% if check_meta and 'github_url' in meta %}
<!-- User defined GitHub URL -->
<a href="{{ meta['github_url'] }}" class="fa fa-github"> {{ _('Edit on GitHub') }}</a>
{% else %}
<a href="https://{{ github_host|default("github.com") }}/{{ github_user }}/{{ github_repo }}/{{ theme_vcs_pageview_mode|default("blob") }}/{{ github_version }}{{ conf_py_path }}{{ pagename }}{{ suffix }}" class="fa fa-github"> {{ _('Edit on GitHub') }}</a>
{% endif %}
{% elif display_bitbucket %}
{% if check_meta and 'bitbucket_url' in meta %}
<!-- User defined Bitbucket URL -->
<a href="{{ meta['bitbucket_url'] }}" class="fa fa-bitbucket"> {{ _('Edit on Bitbucket') }}</a>
{% else %}
<a href="https://bitbucket.org/{{ bitbucket_user }}/{{ bitbucket_repo }}/src/{{ bitbucket_version}}{{ conf_py_path }}{{ pagename }}{{ suffix }}?mode={{ theme_vcs_pageview_mode|default("view") }}" class="fa fa-bitbucket"> {{ _('Edit on Bitbucket') }}</a>
{% endif %}
{% elif display_gitlab %}
{% if check_meta and 'gitlab_url' in meta %}
<!-- User defined GitLab URL -->
<a href="{{ meta['gitlab_url'] }}" class="fa fa-gitlab"> {{ _('Edit on GitLab') }}</a>
{% else %}
<a href="https://{{ gitlab_host|default("gitlab.com") }}/{{ gitlab_user }}/{{ gitlab_repo }}/{{ theme_vcs_pageview_mode|default("blob") }}/{{ gitlab_version }}{{ conf_py_path }}{{ pagename }}{{ suffix }}" class="fa fa-gitlab"> {{ _('Edit on GitLab') }}</a>
{% endif %}
{% elif show_source and source_url_prefix %}
<a href="{{ source_url_prefix }}{{ pagename }}{{ suffix }}">{{ _('View page source') }}</a>
{% elif show_source and has_source and sourcename %}
<a href="{{ pathto('_sources/' + sourcename, true)|e }}" rel="nofollow"> {{ _('View page source') }}</a>
{% endif %}
{% endif %}
</li>
{% endblock %}
</ul>
{% if (theme_prev_next_buttons_location == 'top' or theme_prev_next_buttons_location == 'both') and (next or prev) %}
<div class="rst-breadcrumbs-buttons" role="navigation" aria-label="breadcrumb navigation">
{% if next %}
<a href="{{ next.link|e }}" class="btn btn-neutral float-right" title="{{ next.title|striptags|e }}" accesskey="n">{{ _('Next') }} <span class="fa fa-arrow-circle-right"></span></a>
{% endif %}
{% if prev %}
<a href="{{ prev.link|e }}" class="btn btn-neutral float-left" title="{{ prev.title|striptags|e }}" accesskey="p"><span class="fa fa-arrow-circle-left"></span> {{ _('Previous') }}</a>
{% endif %}
</div>
{% endif %}
<hr/>
</div>

View File

@ -0,0 +1,56 @@
<footer>
{% if (theme_prev_next_buttons_location == 'bottom' or theme_prev_next_buttons_location == 'both') and (next or prev) %}
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
{% if next %}
<a href="{{ next.link|e }}" class="btn btn-neutral float-right" title="{{ next.title|striptags|e }}" accesskey="n" rel="next">{{ _('Next') }} <span class="fa fa-arrow-circle-right"></span></a>
{% endif %}
{% if prev %}
<a href="{{ prev.link|e }}" class="btn btn-neutral float-left" title="{{ prev.title|striptags|e }}" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left"></span> {{ _('Previous') }}</a>
{% endif %}
</div>
{% endif %}
<hr/>
<div role="contentinfo">
<p>
{%- if show_copyright %}
{%- if hasdoc('copyright') %}
{% set path = pathto('copyright') %}
{% set copyright = copyright|e %}
&copy; <a href="{{ path }}">{% trans %}Copyright{% endtrans %}</a> {{ copyright }}
{%- else %}
{% set copyright = copyright|e %}
&copy; {% trans %}Copyright{% endtrans %} {{ copyright }}
{%- endif %}
{%- endif %}
{%- if build_id and build_url %}
<span class="build">
{# Translators: Build is a noun, not a verb #}
{% trans %}Build{% endtrans %}
<a href="{{ build_url }}">{{ build_id }}</a>.
</span>
{%- elif commit %}
<span class="commit">
{% trans %}Revision{% endtrans %} <code>{{ commit }}</code>.
</span>
{%- elif last_updated %}
<span class="lastupdated">
{% trans last_updated=last_updated|e %}Last updated on {{ last_updated }}.{% endtrans %}
</span>
{%- endif %}
</p>
</div>
{%- if show_sphinx %}
{% set sphinx_web = '<a href="http://sphinx-doc.org/">Sphinx</a>' %}
{% set readthedocs_web = '<a href="https://readthedocs.org">Read the Docs</a>' %}
{% trans sphinx_web=sphinx_web, readthedocs_web=readthedocs_web %}Built with {{ sphinx_web }} using a{% endtrans %} <a href="https://github.com/rtfd/sphinx_rtd_theme">{% trans %}theme{% endtrans %}</a> {% trans %}provided by {{ readthedocs_web }}{% endtrans %}.
{%- endif %}
{%- block extrafooter %} {% endblock %}
</footer>

View File

@ -0,0 +1,240 @@
{# TEMPLATE VAR SETTINGS #}
{%- set url_root = pathto('', 1) %}
{%- if url_root == '#' %}{% set url_root = '' %}{% endif %}
{%- if not embedded and docstitle %}
{%- set titlesuffix = " &mdash; "|safe + docstitle|e %}
{%- else %}
{%- set titlesuffix = "" %}
{%- endif %}
{%- set lang_attr = 'en' if language == None else (language | replace('_', '-')) %}
<!DOCTYPE html>
<html lang="{{ lang_attr }}" >
<head>
<meta charset="utf-8">
{{ metatags }}
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{% block htmltitle %}
<title>{{ title|striptags|e }}{{ titlesuffix }}</title>
{% endblock %}
{# CSS #}
<link rel="stylesheet" href="{{ pathto('_static/' + style, 1) }}" type="text/css" />
<link rel="stylesheet" href="{{ pathto('_static/pygments.css', 1) }}" type="text/css" />
{%- for css in css_files %}
{%- if css|attr("rel") %}
<link rel="{{ css.rel }}" href="{{ pathto(css.filename, 1) }}" type="text/css"{% if css.title is not none %} title="{{ css.title }}"{% endif %} />
{%- else %}
<link rel="stylesheet" href="{{ pathto(css, 1) }}" type="text/css" />
{%- endif %}
{%- endfor %}
{%- for cssfile in extra_css_files %}
<link rel="stylesheet" href="{{ pathto(cssfile, 1) }}" type="text/css" />
{%- endfor %}
{# FAVICON #}
{% if favicon %}
<link rel="shortcut icon" href="{{ pathto('_static/' + favicon, 1) }}"/>
{% endif %}
{# CANONICAL URL #}
{% if theme_canonical_url %}
<link rel="canonical" href="{{ theme_canonical_url }}{{ pagename }}.html"/>
{% endif %}
{# JAVASCRIPTS #}
{%- block scripts %}
<!--[if lt IE 9]>
<script src="{{ pathto('_static/js/html5shiv.min.js', 1) }}"></script>
<![endif]-->
{%- if not embedded %}
{# XXX Sphinx 1.8.0 made this an external js-file, quick fix until we refactor the template to inherert more blocks directly from sphinx #}
{% if sphinx_version >= "1.8.0" %}
<script type="text/javascript" id="documentation_options" data-url_root="{{ pathto('', 1) }}" src="{{ pathto('_static/documentation_options.js', 1) }}"></script>
{%- for scriptfile in script_files %}
{{ js_tag(scriptfile) }}
{%- endfor %}
{% else %}
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT:'{{ url_root }}',
VERSION:'{{ release|e }}',
LANGUAGE:'{{ language }}',
COLLAPSE_INDEX:false,
FILE_SUFFIX:'{{ '' if no_search_suffix else file_suffix }}',
HAS_SOURCE: {{ has_source|lower }},
SOURCELINK_SUFFIX: '{{ sourcelink_suffix }}'
};
</script>
{%- for scriptfile in script_files %}
<script type="text/javascript" src="{{ pathto(scriptfile, 1) }}"></script>
{%- endfor %}
{% endif %}
<script type="text/javascript" src="{{ pathto('_static/js/theme.js', 1) }}"></script>
{# OPENSEARCH #}
{%- if use_opensearch %}
<link rel="search" type="application/opensearchdescription+xml"
title="{% trans docstitle=docstitle|e %}Search within {{ docstitle }}{% endtrans %}"
href="{{ pathto('_static/opensearch.xml', 1) }}"/>
{%- endif %}
{%- endif %}
{%- endblock %}
{%- block linktags %}
{%- if hasdoc('about') %}
<link rel="author" title="{{ _('About these documents') }}" href="{{ pathto('about') }}" />
{%- endif %}
{%- if hasdoc('genindex') %}
<link rel="index" title="{{ _('Index') }}" href="{{ pathto('genindex') }}" />
{%- endif %}
{%- if hasdoc('search') %}
<link rel="search" title="{{ _('Search') }}" href="{{ pathto('search') }}" />
{%- endif %}
{%- if hasdoc('copyright') %}
<link rel="copyright" title="{{ _('Copyright') }}" href="{{ pathto('copyright') }}" />
{%- endif %}
{%- if next %}
<link rel="next" title="{{ next.title|striptags|e }}" href="{{ next.link|e }}" />
{%- endif %}
{%- if prev %}
<link rel="prev" title="{{ prev.title|striptags|e }}" href="{{ prev.link|e }}" />
{%- endif %}
{%- endblock %}
{%- block extrahead %} {% endblock %}
</head>
<body class="wy-body-for-nav">
{% block extrabody %} {% endblock %}
<div class="wy-grid-for-nav">
{# SIDE NAV, TOGGLES ON MOBILE #}
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" {% if theme_style_nav_header_background %} style="background: {{theme_style_nav_header_background}}" {% endif %}>
{% block sidebartitle %}
{% if logo and theme_logo_only %}
<a href="{{ pathto(master_doc) }}">
{% else %}
<a href="{{ pathto(master_doc) }}" class="icon icon-home" alt="{{ _("Documentation Home") }}"> {{ project }}
{% endif %}
{% if logo %}
{# Not strictly valid HTML, but it's the only way to display/scale
it properly, without weird scripting or heaps of work
#}
<img src="{{ pathto('_static/' + logo, 1) }}" class="logo" alt="{{ _('Logo') }}"/>
{% endif %}
</a>
{% if theme_display_version %}
{%- set nav_version = version %}
{% if READTHEDOCS and current_version %}
{%- set nav_version = current_version %}
{% endif %}
{% if nav_version %}
<div class="version">
{{ nav_version }}
</div>
{% endif %}
{% endif %}
{% include "searchbox.html" %}
{% endblock %}
</div>
{% block navigation %}
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
{% block menu %}
{#
The singlehtml builder doesn't handle this toctree call when the
toctree is empty. Skip building this for now.
#}
{% if 'singlehtml' not in builder %}
{% set global_toc = toctree(maxdepth=theme_navigation_depth|int,
collapse=theme_collapse_navigation|tobool,
includehidden=theme_includehidden|tobool,
titles_only=theme_titles_only|tobool) %}
{% endif %}
{% if global_toc %}
{{ global_toc }}
{% else %}
<!-- Local TOC -->
<div class="local-toc">{{ toc }}</div>
{% endif %}
{% endblock %}
</div>
{% endblock %}
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
{# MOBILE NAV, TRIGGLES SIDE NAV ON TOGGLE #}
<nav class="wy-nav-top" aria-label="top navigation">
{% block mobile_nav %}
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="{{ pathto(master_doc) }}">{{ project }}</a>
{% endblock %}
</nav>
<div class="wy-nav-content">
{%- block content %}
{% if theme_style_external_links|tobool %}
<div class="rst-content style-external-links">
{% else %}
<div class="rst-content">
{% endif %}
{% include "breadcrumbs.html" %}
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
{%- block document %}
<div itemprop="articleBody">
{% block body %}{% endblock %}
</div>
{% if self.comments()|trim %}
<div class="articleComments">
{% block comments %}{% endblock %}
</div>
{% endif%}
</div>
{%- endblock %}
{% include "footer.html" %}
</div>
{%- endblock %}
</div>
</section>
</div>
{% include "versions.html" %}
<script type="text/javascript">
jQuery(function () {
SphinxRtdTheme.Navigation.enable({{ 'true' if theme_sticky_navigation|tobool else 'false' }});
});
</script>
{# Do not conflict with RTD insertion of analytics script #}
{% if not READTHEDOCS %}
{% if theme_analytics_id %}
<!-- Theme Analytics -->
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', '{{ theme_analytics_id }}', 'auto');
ga('send', 'pageview');
</script>
{% endif %}
{% endif %}
{%- block footer %} {% endblock %}
</body>
</html>

Binary file not shown.

View File

@ -0,0 +1,208 @@
# German translations for sphinx_rtd_theme.
# Copyright (C) 2018 Read the Docs
# This file is distributed under the same license as the sphinx_rtd_theme
# project.
# Dennis Wegner <dennis@instant-thinking.de>, 2018.
msgid ""
msgstr ""
"Project-Id-Version: sphinx_rtd_theme 0.2.4\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2019-07-24 23:51-0600\n"
"PO-Revision-Date: 2020-01-30 12:53+0100\n"
"Last-Translator: Jan Niklas Hasse <jhasse@bixense.com>\n"
"Language-Team: German Team\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Generated-By: Babel 2.4.0\n"
"X-Generator: Poedit 2.2.4\n"
#: sphinx_rtd_theme/breadcrumbs.html:31
msgid "Docs"
msgstr "Dokumente"
#: sphinx_rtd_theme/breadcrumbs.html:43 sphinx_rtd_theme/breadcrumbs.html:45
msgid "Edit on GitHub"
msgstr "Auf GitHub bearbeiten"
#: sphinx_rtd_theme/breadcrumbs.html:50 sphinx_rtd_theme/breadcrumbs.html:52
msgid "Edit on Bitbucket"
msgstr "Auf Bitbucket bearbeiten"
#: sphinx_rtd_theme/breadcrumbs.html:57 sphinx_rtd_theme/breadcrumbs.html:59
msgid "Edit on GitLab"
msgstr "Auf GitLab bearbeiten"
#: sphinx_rtd_theme/breadcrumbs.html:62 sphinx_rtd_theme/breadcrumbs.html:64
msgid "View page source"
msgstr "Seitenquelltext anzeigen"
#: sphinx_rtd_theme/breadcrumbs.html:74 sphinx_rtd_theme/footer.html:5
msgid "Next"
msgstr "Weiter"
#: sphinx_rtd_theme/breadcrumbs.html:77 sphinx_rtd_theme/footer.html:8
msgid "Previous"
msgstr "Zurück"
#: sphinx_rtd_theme/footer.html:21 sphinx_rtd_theme/footer.html:24
#: sphinx_rtd_theme/layout.html:92
msgid "Copyright"
msgstr "Copyright"
#. Build is a noun, not a verb
#: sphinx_rtd_theme/footer.html:31
msgid "Build"
msgstr "Build"
#: sphinx_rtd_theme/footer.html:36
msgid "Revision"
msgstr "Revision"
#: sphinx_rtd_theme/footer.html:40
#, python-format
msgid "Last updated on %(last_updated)s."
msgstr "Zuletzt aktualisiert am %(last_updated)s."
#: sphinx_rtd_theme/footer.html:50
#, python-format
msgid "Built with %(sphinx_web)s using a"
msgstr "Erstellt mit %(sphinx_web)s unter Verwendung eines"
#: sphinx_rtd_theme/footer.html:50
msgid "theme"
msgstr "Themes"
#: sphinx_rtd_theme/footer.html:50
#, python-format
msgid "provided by %(readthedocs_web)s"
msgstr "von %(readthedocs_web)s"
#: sphinx_rtd_theme/layout.html:61
#, python-format
msgid "Search within %(docstitle)s"
msgstr "Suche in %(docstitle)s"
#: sphinx_rtd_theme/layout.html:83
msgid "About these documents"
msgstr "Über diese Dokumente"
#: sphinx_rtd_theme/layout.html:86
msgid "Index"
msgstr "Index"
#: sphinx_rtd_theme/layout.html:89 sphinx_rtd_theme/search.html:11
msgid "Search"
msgstr "Suche"
#: sphinx_rtd_theme/layout.html:124
msgid "Logo"
msgstr "Logo"
#: sphinx_rtd_theme/search.html:26
msgid "Please activate JavaScript to enable the search functionality."
msgstr "Bitte JavaScript aktivieren um die Suchfunktion zu ermöglichen."
#. Search is a noun, not a verb
#: sphinx_rtd_theme/search.html:34
msgid "Search Results"
msgstr "Suchergebnisse"
#: sphinx_rtd_theme/search.html:36
msgid ""
"Your search did not match any documents. Please make sure that all words are "
"spelled correctly and that you've selected enough categories."
msgstr ""
"Deine Suche ergab keine Treffer. Bitte stelle sicher, dass alle Wörter "
"richtig geschrieben sind und du genug Kategorien ausgewählt hast."
#: sphinx_rtd_theme/searchbox.html:4
msgid "Search docs"
msgstr "Dokumentation durchsuchen"
#: sphinx_rtd_theme/versions.html:11
msgid "Versions"
msgstr "Versionen"
#: sphinx_rtd_theme/versions.html:17
msgid "Downloads"
msgstr "Downloads"
#. The phrase "Read the Docs" is not translated
#: sphinx_rtd_theme/versions.html:24
msgid "On Read the Docs"
msgstr "Auf Read the Docs"
#: sphinx_rtd_theme/versions.html:26
msgid "Project Home"
msgstr "Projektseite"
#: sphinx_rtd_theme/versions.html:29
msgid "Builds"
msgstr "Builds"
#: sphinx_rtd_theme/versions.html:33
msgid "Free document hosting provided by"
msgstr "Kostenloses Dokumenten-Hosting von"
#~ msgid "&copy; <a href=\"%(path)s\">Copyright</a> %(copyright)s."
#~ msgstr "&copy; <a href=\\\"%(path)s\\\">Copyright</a> %(copyright)s."
#~ msgid "&copy; Copyright %(copyright)s."
#~ msgstr "&copy; Copyright %(copyright)s."
#~ msgid ""
#~ "\n"
#~ " <span class=\"build\">\n"
#~ " Build\n"
#~ " <a href=\"%(build_url)s\">%(build_id)s</a>.\n"
#~ " </span>\n"
#~ " "
#~ msgstr ""
#~ "\n"
#~ " <span class=\"build\">\n"
#~ " Build\n"
#~ " <a href=\"%(build_url)s\">%(build_id)s</a>.\n"
#~ " </span>\n"
#~ " "
#~ msgid ""
#~ "\n"
#~ " <span class=\"commit\">\n"
#~ " Revision <code>%(commit)s</code>.\n"
#~ " </span>\n"
#~ " "
#~ msgstr ""
#~ "\n"
#~ " <span class=\"commit\">\n"
#~ " Revision <code>%(commit)s</code>.\n"
#~ " </span>\n"
#~ " "
#~ msgid ""
#~ "Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href="
#~ "\"https://github.com/snide/sphinx_rtd_theme\">theme</a> provided by <a "
#~ "href=\"https://readthedocs.org\">Read the Docs</a>"
#~ msgstr ""
#~ "Erstellt mit <a href=\"http://sphinx-doc.org/\">Sphinx</a> unter "
#~ "Verwendung eines <a href=\"https://github.com/snide/sphinx_rtd_theme"
#~ "\">Themes</a> von <a href=\"https://readthedocs.org\">Read the Docs</a>"
#~ msgid "Navigation"
#~ msgstr "Navigation"
#~ msgid ""
#~ "Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> "
#~ "%(sphinx_version)s."
#~ msgstr ""
#~ "Erstellt mit <a href=\"http://sphinx-doc.org/\">Sphinx</a> "
#~ "%(sphinx_version)s."
#~ msgid ""
#~ "Free document hosting provided by <a href=\"http://www.readthedocs.org"
#~ "\">Read the Docs</a>."
#~ msgstr ""
#~ "Dokumentationshosting gratis bei <a href=\"http://www.readthedocs.org"
#~ "\">Read the Docs</a>."

Binary file not shown.

View File

@ -0,0 +1,147 @@
# English translations for sphinx_rtd_theme.
# Copyright (C) 2019 ORGANIZATION
# This file is distributed under the same license as the sphinx_rtd_theme
# project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2019.
#
msgid ""
msgstr ""
"Project-Id-Version: sphinx_rtd_theme 0.4.3.dev0\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2019-07-24 23:51-0600\n"
"PO-Revision-Date: 2019-07-16 15:43-0600\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language: en\n"
"Language-Team: en <LL@li.org>\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.7.0\n"
#: sphinx_rtd_theme/breadcrumbs.html:31
msgid "Docs"
msgstr ""
#: sphinx_rtd_theme/breadcrumbs.html:43 sphinx_rtd_theme/breadcrumbs.html:45
msgid "Edit on GitHub"
msgstr ""
#: sphinx_rtd_theme/breadcrumbs.html:50 sphinx_rtd_theme/breadcrumbs.html:52
msgid "Edit on Bitbucket"
msgstr ""
#: sphinx_rtd_theme/breadcrumbs.html:57 sphinx_rtd_theme/breadcrumbs.html:59
msgid "Edit on GitLab"
msgstr ""
#: sphinx_rtd_theme/breadcrumbs.html:62 sphinx_rtd_theme/breadcrumbs.html:64
msgid "View page source"
msgstr ""
#: sphinx_rtd_theme/breadcrumbs.html:74 sphinx_rtd_theme/footer.html:5
msgid "Next"
msgstr ""
#: sphinx_rtd_theme/breadcrumbs.html:77 sphinx_rtd_theme/footer.html:8
msgid "Previous"
msgstr ""
#: sphinx_rtd_theme/footer.html:21 sphinx_rtd_theme/footer.html:24
#: sphinx_rtd_theme/layout.html:92
msgid "Copyright"
msgstr ""
#. Build is a noun, not a verb
#: sphinx_rtd_theme/footer.html:31
msgid "Build"
msgstr ""
#: sphinx_rtd_theme/footer.html:36
msgid "Revision"
msgstr ""
#: sphinx_rtd_theme/footer.html:40
#, python-format
msgid "Last updated on %(last_updated)s."
msgstr ""
#: sphinx_rtd_theme/footer.html:50
#, python-format
msgid "Built with %(sphinx_web)s using a"
msgstr ""
#: sphinx_rtd_theme/footer.html:50
msgid "theme"
msgstr ""
#: sphinx_rtd_theme/footer.html:50
#, python-format
msgid "provided by %(readthedocs_web)s"
msgstr ""
#: sphinx_rtd_theme/layout.html:61
#, python-format
msgid "Search within %(docstitle)s"
msgstr ""
#: sphinx_rtd_theme/layout.html:83
msgid "About these documents"
msgstr ""
#: sphinx_rtd_theme/layout.html:86
msgid "Index"
msgstr ""
#: sphinx_rtd_theme/layout.html:89 sphinx_rtd_theme/search.html:11
msgid "Search"
msgstr ""
#: sphinx_rtd_theme/layout.html:124
msgid "Logo"
msgstr ""
#: sphinx_rtd_theme/search.html:26
msgid "Please activate JavaScript to enable the search functionality."
msgstr ""
#. Search is a noun, not a verb
#: sphinx_rtd_theme/search.html:34
msgid "Search Results"
msgstr ""
#: sphinx_rtd_theme/search.html:36
msgid ""
"Your search did not match any documents. Please make sure that all words "
"are spelled correctly and that you've selected enough categories."
msgstr ""
#: sphinx_rtd_theme/searchbox.html:4
msgid "Search docs"
msgstr ""
#: sphinx_rtd_theme/versions.html:11
msgid "Versions"
msgstr ""
#: sphinx_rtd_theme/versions.html:17
msgid "Downloads"
msgstr ""
#. The phrase "Read the Docs" is not translated
#: sphinx_rtd_theme/versions.html:24
msgid "On Read the Docs"
msgstr ""
#: sphinx_rtd_theme/versions.html:26
msgid "Project Home"
msgstr ""
#: sphinx_rtd_theme/versions.html:29
msgid "Builds"
msgstr ""
#: sphinx_rtd_theme/versions.html:33
msgid "Free document hosting provided by"
msgstr ""

Binary file not shown.

View File

@ -0,0 +1,149 @@
# Spanish translations for sphinx_rtd_theme.
# Copyright (C) 2019 Read the Docs, Inc
# This file is distributed under the same license as the sphinx_rtd_theme
# project.
msgid ""
msgstr ""
"Project-Id-Version: sphinx_rtd_theme 0.4.3.dev0\n"
"Report-Msgid-Bugs-To: support@readthedocs.org\n"
"POT-Creation-Date: 2019-07-24 23:51-0600\n"
"PO-Revision-Date: 2019-07-16 21:44+0000\n"
"Last-Translator: Anthony <aj@ohess.org>, 2019\n"
"Language: es\n"
"Language-Team: Spanish "
"(https://www.transifex.com/readthedocs/teams/101354/es/)\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.7.0\n"
#: sphinx_rtd_theme/breadcrumbs.html:31
msgid "Docs"
msgstr "Documentos"
#: sphinx_rtd_theme/breadcrumbs.html:43 sphinx_rtd_theme/breadcrumbs.html:45
msgid "Edit on GitHub"
msgstr "Editar en GitHub"
#: sphinx_rtd_theme/breadcrumbs.html:50 sphinx_rtd_theme/breadcrumbs.html:52
msgid "Edit on Bitbucket"
msgstr "Editar en Bitbucket"
#: sphinx_rtd_theme/breadcrumbs.html:57 sphinx_rtd_theme/breadcrumbs.html:59
msgid "Edit on GitLab"
msgstr "Editar en GitLab"
#: sphinx_rtd_theme/breadcrumbs.html:62 sphinx_rtd_theme/breadcrumbs.html:64
msgid "View page source"
msgstr "Ver código fuente de la página"
#: sphinx_rtd_theme/breadcrumbs.html:74 sphinx_rtd_theme/footer.html:5
msgid "Next"
msgstr "Siguiente"
#: sphinx_rtd_theme/breadcrumbs.html:77 sphinx_rtd_theme/footer.html:8
msgid "Previous"
msgstr "Anterior"
#: sphinx_rtd_theme/footer.html:21 sphinx_rtd_theme/footer.html:24
#: sphinx_rtd_theme/layout.html:92
msgid "Copyright"
msgstr "Derechos de autor"
#. Build is a noun, not a verb
#: sphinx_rtd_theme/footer.html:31
msgid "Build"
msgstr "Construido"
#: sphinx_rtd_theme/footer.html:36
msgid "Revision"
msgstr "Revisión"
#: sphinx_rtd_theme/footer.html:40
#, python-format
msgid "Last updated on %(last_updated)s."
msgstr "Actualizado por última vez en %(last_updated)s."
#: sphinx_rtd_theme/footer.html:50
#, python-format
msgid "Built with %(sphinx_web)s using a"
msgstr "Construido con %(sphinx_web)s usando un"
#: sphinx_rtd_theme/footer.html:50
msgid "theme"
msgstr "tema"
#: sphinx_rtd_theme/footer.html:50
#, python-format
msgid "provided by %(readthedocs_web)s"
msgstr "proporcionado por %(readthedocs_web)s"
#: sphinx_rtd_theme/layout.html:61
#, python-format
msgid "Search within %(docstitle)s"
msgstr "Buscar en %(docstitle)s"
#: sphinx_rtd_theme/layout.html:83
msgid "About these documents"
msgstr "Sobre esta documentación"
#: sphinx_rtd_theme/layout.html:86
msgid "Index"
msgstr "Índice"
#: sphinx_rtd_theme/layout.html:89 sphinx_rtd_theme/search.html:11
msgid "Search"
msgstr "Búsqueda"
#: sphinx_rtd_theme/layout.html:124
msgid "Logo"
msgstr "Logotipo"
#: sphinx_rtd_theme/search.html:26
msgid "Please activate JavaScript to enable the search functionality."
msgstr "Por favor, active JavaScript para habilitar la funcionalidad de búsqueda."
#. Search is a noun, not a verb
#: sphinx_rtd_theme/search.html:34
msgid "Search Results"
msgstr "Resultados de la búsqueda"
#: sphinx_rtd_theme/search.html:36
msgid ""
"Your search did not match any documents. Please make sure that all words "
"are spelled correctly and that you've selected enough categories."
msgstr ""
"Su búsqueda no coincide con ningún documento. Por favor, asegúrese de que"
" todas las palabras estén correctamente escritas y que usted haya "
"seleccionado las suficientes categorías."
#: sphinx_rtd_theme/searchbox.html:4
msgid "Search docs"
msgstr "Buscar documentos"
#: sphinx_rtd_theme/versions.html:11
msgid "Versions"
msgstr "Versiones"
#: sphinx_rtd_theme/versions.html:17
msgid "Downloads"
msgstr "Descargas"
#. The phrase "Read the Docs" is not translated
#: sphinx_rtd_theme/versions.html:24
msgid "On Read the Docs"
msgstr "En Read the Docs"
#: sphinx_rtd_theme/versions.html:26
msgid "Project Home"
msgstr "Página de Proyecto"
#: sphinx_rtd_theme/versions.html:29
msgid "Builds"
msgstr "Construcciones"
#: sphinx_rtd_theme/versions.html:33
msgid "Free document hosting provided by"
msgstr "Alojamiento gratuito de documentos proporcionado por"

Binary file not shown.

View File

@ -0,0 +1,152 @@
# English translations for sphinx_rtd_theme.
# Copyright (C) 2019 ORGANIZATION
# This file is distributed under the same license as the sphinx_rtd_theme
# project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2019.
#
# Translators:
# Jesse Tan, 2019
msgid ""
msgstr ""
"Project-Id-Version: sphinx_rtd_theme 0.4.3.dev0\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2019-07-24 23:51-0600\n"
"PO-Revision-Date: 2019-07-16 21:44+0000\n"
"Last-Translator: Jesse Tan, 2019\n"
"Language: nl\n"
"Language-Team: Dutch "
"(https://www.transifex.com/readthedocs/teams/101354/nl/)\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.7.0\n"
#: sphinx_rtd_theme/breadcrumbs.html:31
msgid "Docs"
msgstr "Documentatie"
#: sphinx_rtd_theme/breadcrumbs.html:43 sphinx_rtd_theme/breadcrumbs.html:45
msgid "Edit on GitHub"
msgstr "Bewerk op GitHub"
#: sphinx_rtd_theme/breadcrumbs.html:50 sphinx_rtd_theme/breadcrumbs.html:52
msgid "Edit on Bitbucket"
msgstr "Bewerk op BitBucket"
#: sphinx_rtd_theme/breadcrumbs.html:57 sphinx_rtd_theme/breadcrumbs.html:59
msgid "Edit on GitLab"
msgstr "Bewerk op GitLab"
#: sphinx_rtd_theme/breadcrumbs.html:62 sphinx_rtd_theme/breadcrumbs.html:64
msgid "View page source"
msgstr "Bekijk paginabron"
#: sphinx_rtd_theme/breadcrumbs.html:74 sphinx_rtd_theme/footer.html:5
msgid "Next"
msgstr "Volgende"
#: sphinx_rtd_theme/breadcrumbs.html:77 sphinx_rtd_theme/footer.html:8
msgid "Previous"
msgstr "Vorige"
#: sphinx_rtd_theme/footer.html:21 sphinx_rtd_theme/footer.html:24
#: sphinx_rtd_theme/layout.html:92
msgid "Copyright"
msgstr "Copyright"
#. Build is a noun, not a verb
#: sphinx_rtd_theme/footer.html:31
msgid "Build"
msgstr "Bouwsel"
#: sphinx_rtd_theme/footer.html:36
msgid "Revision"
msgstr "Revisie"
#: sphinx_rtd_theme/footer.html:40
#, python-format
msgid "Last updated on %(last_updated)s."
msgstr "Laatste update op %(last_updated)s."
#: sphinx_rtd_theme/footer.html:50
#, python-format
msgid "Built with %(sphinx_web)s using a"
msgstr "Gebouwd met %(sphinx_web)s met een"
#: sphinx_rtd_theme/footer.html:50
msgid "theme"
msgstr "thema"
#: sphinx_rtd_theme/footer.html:50
#, python-format
msgid "provided by %(readthedocs_web)s"
msgstr "geleverd door %(readthedocs_web)s"
#: sphinx_rtd_theme/layout.html:61
#, python-format
msgid "Search within %(docstitle)s"
msgstr "Zoek binnen %(docstitle)s"
#: sphinx_rtd_theme/layout.html:83
msgid "About these documents"
msgstr "Over deze documenten"
#: sphinx_rtd_theme/layout.html:86
msgid "Index"
msgstr "Index"
#: sphinx_rtd_theme/layout.html:89 sphinx_rtd_theme/search.html:11
msgid "Search"
msgstr "Zoek"
#: sphinx_rtd_theme/layout.html:124
msgid "Logo"
msgstr "Logo"
#: sphinx_rtd_theme/search.html:26
msgid "Please activate JavaScript to enable the search functionality."
msgstr "Zet JavaScript aan om de zoekfunctie mogelijk te maken."
#. Search is a noun, not a verb
#: sphinx_rtd_theme/search.html:34
msgid "Search Results"
msgstr "Zoekresultaten"
#: sphinx_rtd_theme/search.html:36
msgid ""
"Your search did not match any documents. Please make sure that all words "
"are spelled correctly and that you've selected enough categories."
msgstr ""
"Zoekpoging vond geen documenten. Zorg ervoor dat alle woorden correct "
"zijn gespeld en dat voldoende categorieën zijn geselecteerd."
#: sphinx_rtd_theme/searchbox.html:4
msgid "Search docs"
msgstr "Zoek in documentatie"
#: sphinx_rtd_theme/versions.html:11
msgid "Versions"
msgstr "Versies"
#: sphinx_rtd_theme/versions.html:17
msgid "Downloads"
msgstr "Downloads"
#. The phrase "Read the Docs" is not translated
#: sphinx_rtd_theme/versions.html:24
msgid "On Read the Docs"
msgstr "Op Read the Docs"
#: sphinx_rtd_theme/versions.html:26
msgid "Project Home"
msgstr "Project Home"
#: sphinx_rtd_theme/versions.html:29
msgid "Builds"
msgstr "Bouwsels"
#: sphinx_rtd_theme/versions.html:33
msgid "Free document hosting provided by"
msgstr "Gratis hosting voor documentatie verzorgd door"

Binary file not shown.

View File

@ -0,0 +1,148 @@
# Russian translations for sphinx_rtd_theme.
# Copyright (C) 2019 Read the Docs, Inc
# This file is distributed under the same license as the sphinx_rtd_theme
# project.
msgid ""
msgstr ""
"Project-Id-Version: sphinx_rtd_theme 0.4.3.dev0\n"
"Report-Msgid-Bugs-To: support@readthedocs.org\n"
"POT-Creation-Date: 2019-07-24 23:51-0600\n"
"PO-Revision-Date: 2019-07-16 21:44+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language: ru\n"
"Language-Team: Russian "
"(https://www.transifex.com/readthedocs/teams/101354/ru/)\n"
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
"n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) "
"|| (n%100>=11 && n%100<=14)? 2 : 3)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.7.0\n"
#: sphinx_rtd_theme/breadcrumbs.html:31
msgid "Docs"
msgstr ""
#: sphinx_rtd_theme/breadcrumbs.html:43 sphinx_rtd_theme/breadcrumbs.html:45
msgid "Edit on GitHub"
msgstr ""
#: sphinx_rtd_theme/breadcrumbs.html:50 sphinx_rtd_theme/breadcrumbs.html:52
msgid "Edit on Bitbucket"
msgstr ""
#: sphinx_rtd_theme/breadcrumbs.html:57 sphinx_rtd_theme/breadcrumbs.html:59
msgid "Edit on GitLab"
msgstr ""
#: sphinx_rtd_theme/breadcrumbs.html:62 sphinx_rtd_theme/breadcrumbs.html:64
msgid "View page source"
msgstr ""
#: sphinx_rtd_theme/breadcrumbs.html:74 sphinx_rtd_theme/footer.html:5
msgid "Next"
msgstr ""
#: sphinx_rtd_theme/breadcrumbs.html:77 sphinx_rtd_theme/footer.html:8
msgid "Previous"
msgstr ""
#: sphinx_rtd_theme/footer.html:21 sphinx_rtd_theme/footer.html:24
#: sphinx_rtd_theme/layout.html:92
msgid "Copyright"
msgstr ""
#. Build is a noun, not a verb
#: sphinx_rtd_theme/footer.html:31
msgid "Build"
msgstr ""
#: sphinx_rtd_theme/footer.html:36
msgid "Revision"
msgstr ""
#: sphinx_rtd_theme/footer.html:40
#, python-format
msgid "Last updated on %(last_updated)s."
msgstr ""
#: sphinx_rtd_theme/footer.html:50
#, python-format
msgid "Built with %(sphinx_web)s using a"
msgstr ""
#: sphinx_rtd_theme/footer.html:50
msgid "theme"
msgstr ""
#: sphinx_rtd_theme/footer.html:50
#, python-format
msgid "provided by %(readthedocs_web)s"
msgstr ""
#: sphinx_rtd_theme/layout.html:61
#, python-format
msgid "Search within %(docstitle)s"
msgstr ""
#: sphinx_rtd_theme/layout.html:83
msgid "About these documents"
msgstr ""
#: sphinx_rtd_theme/layout.html:86
msgid "Index"
msgstr ""
#: sphinx_rtd_theme/layout.html:89 sphinx_rtd_theme/search.html:11
msgid "Search"
msgstr ""
#: sphinx_rtd_theme/layout.html:124
msgid "Logo"
msgstr ""
#: sphinx_rtd_theme/search.html:26
msgid "Please activate JavaScript to enable the search functionality."
msgstr ""
#. Search is a noun, not a verb
#: sphinx_rtd_theme/search.html:34
msgid "Search Results"
msgstr ""
#: sphinx_rtd_theme/search.html:36
msgid ""
"Your search did not match any documents. Please make sure that all words "
"are spelled correctly and that you've selected enough categories."
msgstr ""
#: sphinx_rtd_theme/searchbox.html:4
msgid "Search docs"
msgstr ""
#: sphinx_rtd_theme/versions.html:11
msgid "Versions"
msgstr ""
#: sphinx_rtd_theme/versions.html:17
msgid "Downloads"
msgstr ""
#. The phrase "Read the Docs" is not translated
#: sphinx_rtd_theme/versions.html:24
msgid "On Read the Docs"
msgstr ""
#: sphinx_rtd_theme/versions.html:26
msgid "Project Home"
msgstr ""
#: sphinx_rtd_theme/versions.html:29
msgid "Builds"
msgstr ""
#: sphinx_rtd_theme/versions.html:33
msgid "Free document hosting provided by"
msgstr ""

View File

@ -0,0 +1,146 @@
# Translations template for sphinx_rtd_theme.
# Copyright (C) 2019 ORGANIZATION
# This file is distributed under the same license as the sphinx_rtd_theme
# project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2019.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: sphinx_rtd_theme 0.4.3.dev0\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2019-07-24 23:51-0600\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.7.0\n"
#: sphinx_rtd_theme/breadcrumbs.html:31
msgid "Docs"
msgstr ""
#: sphinx_rtd_theme/breadcrumbs.html:43 sphinx_rtd_theme/breadcrumbs.html:45
msgid "Edit on GitHub"
msgstr ""
#: sphinx_rtd_theme/breadcrumbs.html:50 sphinx_rtd_theme/breadcrumbs.html:52
msgid "Edit on Bitbucket"
msgstr ""
#: sphinx_rtd_theme/breadcrumbs.html:57 sphinx_rtd_theme/breadcrumbs.html:59
msgid "Edit on GitLab"
msgstr ""
#: sphinx_rtd_theme/breadcrumbs.html:62 sphinx_rtd_theme/breadcrumbs.html:64
msgid "View page source"
msgstr ""
#: sphinx_rtd_theme/breadcrumbs.html:74 sphinx_rtd_theme/footer.html:5
msgid "Next"
msgstr ""
#: sphinx_rtd_theme/breadcrumbs.html:77 sphinx_rtd_theme/footer.html:8
msgid "Previous"
msgstr ""
#: sphinx_rtd_theme/footer.html:21 sphinx_rtd_theme/footer.html:24
#: sphinx_rtd_theme/layout.html:92
msgid "Copyright"
msgstr ""
#. Build is a noun, not a verb
#: sphinx_rtd_theme/footer.html:31
msgid "Build"
msgstr ""
#: sphinx_rtd_theme/footer.html:36
msgid "Revision"
msgstr ""
#: sphinx_rtd_theme/footer.html:40
#, python-format
msgid "Last updated on %(last_updated)s."
msgstr ""
#: sphinx_rtd_theme/footer.html:50
#, python-format
msgid "Built with %(sphinx_web)s using a"
msgstr ""
#: sphinx_rtd_theme/footer.html:50
msgid "theme"
msgstr ""
#: sphinx_rtd_theme/footer.html:50
#, python-format
msgid "provided by %(readthedocs_web)s"
msgstr ""
#: sphinx_rtd_theme/layout.html:61
#, python-format
msgid "Search within %(docstitle)s"
msgstr ""
#: sphinx_rtd_theme/layout.html:83
msgid "About these documents"
msgstr ""
#: sphinx_rtd_theme/layout.html:86
msgid "Index"
msgstr ""
#: sphinx_rtd_theme/layout.html:89 sphinx_rtd_theme/search.html:11
msgid "Search"
msgstr ""
#: sphinx_rtd_theme/layout.html:124
msgid "Logo"
msgstr ""
#: sphinx_rtd_theme/search.html:26
msgid "Please activate JavaScript to enable the search functionality."
msgstr ""
#. Search is a noun, not a verb
#: sphinx_rtd_theme/search.html:34
msgid "Search Results"
msgstr ""
#: sphinx_rtd_theme/search.html:36
msgid ""
"Your search did not match any documents. Please make sure that all words "
"are spelled correctly and that you've selected enough categories."
msgstr ""
#: sphinx_rtd_theme/searchbox.html:4
msgid "Search docs"
msgstr ""
#: sphinx_rtd_theme/versions.html:11
msgid "Versions"
msgstr ""
#: sphinx_rtd_theme/versions.html:17
msgid "Downloads"
msgstr ""
#. The phrase "Read the Docs" is not translated
#: sphinx_rtd_theme/versions.html:24
msgid "On Read the Docs"
msgstr ""
#: sphinx_rtd_theme/versions.html:26
msgid "Project Home"
msgstr ""
#: sphinx_rtd_theme/versions.html:29
msgid "Builds"
msgstr ""
#: sphinx_rtd_theme/versions.html:33
msgid "Free document hosting provided by"
msgstr ""

View File

@ -0,0 +1,54 @@
{#
basic/search.html
~~~~~~~~~~~~~~~~~
Template for the search page.
:copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
#}
{%- extends "layout.html" %}
{% set title = _('Search') %}
{%- block scripts %}
{{ super() }}
<script type="text/javascript" src="{{ pathto('_static/searchtools.js', 1) }}"></script>
{%- endblock %}
{% block footer %}
<script type="text/javascript">
jQuery(function() { Search.loadIndex("{{ pathto('searchindex.js', 1) }}"); });
</script>
{# this is used when loading the search index using $.ajax fails,
such as on Chrome for documents on localhost #}
<script type="text/javascript" id="searchindexloader"></script>
{{ super() }}
{% endblock %}
{% block body %}
<noscript>
<div id="fallback" class="admonition warning">
<p class="last">
{% trans trimmed %}Please activate JavaScript to enable the search
functionality.{% endtrans %}
</p>
</div>
</noscript>
{% if search_performed %}
{# Translators: Search is a noun, not a verb #}
<h2>{{ _('Search Results') }}</h2>
{% if not search_results %}
<p>{{ _('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.') }}</p>
{% endif %}
{% endif %}
<div id="search-results">
{% if search_results %}
<ul>
{% for href, caption, context in search_results %}
<li>
<a href="{{ pathto(item.href) }}">{{ caption }}</a>
<p class="context">{{ context|e }}</p>
</li>
{% endfor %}
</ul>
{% endif %}
</div>
{% endblock %}

View File

@ -0,0 +1,9 @@
{%- if builder != 'singlehtml' %}
<div role="search">
<form id="rtd-search-form" class="wy-form" action="{{ pathto('search') }}" method="get">
<input type="text" name="q" placeholder="{{ _('Search docs') }}" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
{%- endif %}

View File

@ -0,0 +1 @@
.fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
!function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=4)}({4:function(e,t,r){}});

View File

@ -0,0 +1 @@
!function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap("<div class='wy-table-responsive'></div>"),n("table.docutils.footnote").wrap("<div class='wy-table-responsive footnote'></div>"),n("table.docutils.citation").wrap("<div class='wy-table-responsive citation'></div>"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n('<span class="toctree-expand"></span>'),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}t.length>0&&($(".wy-menu-vertical .current").removeClass("current"),t.addClass("current"),t.closest("li.toctree-l1").addClass("current"),t.closest("li.toctree-l1").parent().addClass("current"),t.closest("li.toctree-l1").addClass("current"),t.closest("li.toctree-l2").addClass("current"),t.closest("li.toctree-l3").addClass("current"),t.closest("li.toctree-l4").addClass("current"),t[0].scrollIntoView())}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current"),e.siblings().find("li.current").removeClass("current"),e.find("> ul li.current").removeClass("current"),e.toggleClass("current")}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t<e.length&&!window.requestAnimationFrame;++t)window.requestAnimationFrame=window[e[t]+"RequestAnimationFrame"],window.cancelAnimationFrame=window[e[t]+"CancelAnimationFrame"]||window[e[t]+"CancelRequestAnimationFrame"];window.requestAnimationFrame||(window.requestAnimationFrame=function(e,t){var i=(new Date).getTime(),o=Math.max(0,16-(i-n)),r=window.setTimeout((function(){e(i+o)}),o);return n=i+o,r}),window.cancelAnimationFrame||(window.cancelAnimationFrame=function(n){clearTimeout(n)})}()}).call(window)},function(n,e){n.exports=jQuery},function(n,e,t){}]);

View File

@ -0,0 +1,18 @@
[theme]
inherit = basic
stylesheet = css/theme.css
pygments_style = default
[options]
canonical_url =
analytics_id =
collapse_navigation = True
sticky_navigation = True
navigation_depth = 4
includehidden = True
titles_only =
logo_only =
display_version = True
prev_next_buttons_location = bottom
style_external_links = False
style_nav_header_background =

View File

@ -0,0 +1,34 @@
{% if READTHEDOCS %}
{# Add rst-badge after rst-versions for small badge style. #}
<div class="rst-versions" data-toggle="rst-versions" role="note" aria-label="versions">
<span class="rst-current-version" data-toggle="rst-current-version">
<span class="fa fa-book"> Read the Docs</span>
v: {{ current_version }}
<span class="fa fa-caret-down"></span>
</span>
<div class="rst-other-versions">
<dl>
<dt>{{ _('Versions') }}</dt>
{% for slug, url in versions %}
<dd><a href="{{ url }}">{{ slug }}</a></dd>
{% endfor %}
</dl>
<dl>
<dt>{{ _('Downloads') }}</dt>
{% for type, url in downloads %}
<dd><a href="{{ url }}">{{ type }}</a></dd>
{% endfor %}
</dl>
<dl>
{# Translators: The phrase "Read the Docs" is not translated #}
<dt>{{ _('On Read the Docs') }}</dt>
<dd>
<a href="//{{ PRODUCTION_DOMAIN }}/projects/{{ slug }}/?fromdocs={{ slug }}">{{ _('Project Home') }}</a>
</dd>
<dd>
<a href="//{{ PRODUCTION_DOMAIN }}/builds/{{ slug }}/?fromdocs={{ slug }}">{{ _('Builds') }}</a>
</dd>
</dl>
</div>
</div>
{% endif %}

146
docs/conf.py Normal file
View File

@ -0,0 +1,146 @@
# 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 subprocess, os, 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',
'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 = []
# -- 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'
html_theme_path = ["_themes", ]
# 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 ---------------------------------------------------
# Check if we're running on Read the Docs' servers
read_the_docs_build = os.environ.get('READTHEDOCS', None) == 'True'
# 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 = {}
if read_the_docs_build:
input_dir = '../src'
output_dir = 'build'
configureDoxyfile(input_dir, output_dir)
subprocess.call('doxygen', shell=True)
breathe_projects['mp-units'] = output_dir + '/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', )
def configureDoxyfile(input_dir, output_dir):
with open('Doxyfile.in', 'r') as file:
filedata = file.read()
filedata = filedata.replace('@DOXYGEN_INPUT_DIR@', input_dir)
filedata = filedata.replace('@DOXYGEN_OUTPUT_DIR@', output_dir)
with open('Doxyfile', 'w') as file:
file.write(filedata)

BIN
docs/design.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

13
docs/design.rst Normal file
View File

@ -0,0 +1,13 @@
Design
======
.. note::
For brevity all the code examples in this documentation will assume::
using namespace units;
.. toctree::
:maxdepth: 2
design/quantity

67
docs/design/quantity.rst Normal file
View File

@ -0,0 +1,67 @@
.. namespace:: units
quantity
========
Interface
---------
`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, Scalar 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_dim<D1, dim_invert<D2>>
[[nodiscard]] constexpr Scalar auto operator*(const quantity<D1, U1, Rep1>& lhs,
const quantity<D2, U2, Rep2>& rhs);
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2>
requires detail::basic_arithmetic<Rep1, Rep2> && (!equivalent_dim<D1, dim_invert<D2>>)
[[nodiscard]] constexpr Quantity auto operator*(const quantity<D1, U1, Rep1>& lhs,
const quantity<D2, U2, Rep2>& rhs);
template<Scalar 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_dim<D1, D2>
[[nodiscard]] constexpr Scalar auto operator/(const quantity<D1, U1, Rep1>& lhs,
const quantity<D2, U2, Rep2>& rhs);
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2>
requires detail::basic_arithmetic<Rep1, Rep2> && (!equivalent_dim<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_dim``
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 ``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 `units::quantity` uses the resulting
type of a concrete operator operation.
2. `operator %` is constrained with `treat_as_floating_point` type trait to limit the
types to integral representations only. Also `operator %(Rep)` takes `Rep` as a
template argument to limit implicit conversions.

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

8
docs/examples.rst Normal file
View File

@ -0,0 +1,8 @@
Examples
========
.. toctree::
:maxdepth: 2
examples/hello_units
examples/avg_speed

View File

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

View File

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

44
docs/faq.rst Normal file
View File

@ -0,0 +1,44 @@
FAQ
===
General
-------
Why all UDLs are prefixed with ``q_`` instead of just using unit symbol?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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.
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 has to know that it 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 do we spell ``metre`` instead of ``meter``?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Well, this is how ISO 80000 defines it (British English spelling by default).

18
docs/framework.rst Normal file
View File

@ -0,0 +1,18 @@
Framework
=========
.. note::
For brevity all the code examples in this documentation will assume::
using namespace units;
.. toctree::
:maxdepth: 2
framework/basic_concepts
framework/quantities
framework/dimensions
framework/units
framework/conversions_and_casting
framework/text_output

View File

@ -0,0 +1,22 @@
.. namespace:: units
Basic Concepts
==============
The most important concepts in the library are `Unit`, `Dimension`, and
`Quantity`:
.. image:: /_static/img/design.png
:align: center
`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.
`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.
`Quantity` is a concrete amount of a unit for a specified dimension with a
specific representation.

View File

@ -0,0 +1,16 @@
.. namespace:: units
Conversions and Casting
=======================
Implicit Conversions
--------------------
constructors
Explicit Casting
----------------
quantity_cast
Example of casting to a dimension's coherent unit.

View File

@ -0,0 +1,178 @@
.. 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, velocity, area, energy are only a few examples of physical
dimensions.
Operations
----------
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 = 2q_m;
Length auto dist2 = 1q_m;
Length auto res1 = dist1 + dist2;
Length auto res2 = dist1 - dist2;
Additionally, we can always multiply or divide a quantity by a
:term:`scalar` and in such a case the quantity's dimension will also
not change:
.. code-block::
:emphasize-lines: 2-4
Length auto dist = 2q_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 scalar 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 = 2q_m;
Length auto dist2 = 3q_m;
Time auto dur1 = 2q_s;
Area auto res1 = dist1 * dist2; // 6 m²
Velocity 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 scalar type:
.. code-block::
:emphasize-lines: 4-5
Time auto dur1 = 10q_s;
Time auto dur2 = 2q_s;
Frequency auto fr1 = 5q_Hz;
Scalar auto v1 = dur1 / dur2; // 5
Scalar auto v2 = dur1 * fr1; // 50
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 `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(std::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.
Looking at the previous code snippets the area, velocity, 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 velocity 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,
exp<dim_length, 2>> {};
struct dim_velocity : derived_dimension<dim_velocity, metre_per_second,
exp<dim_length, 1>, exp<dim_time, -1>> {};
}
In the above code sample `si::square_metre` and `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:`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,
exp<dim_length, 1>, exp<dim_length, 1>> {};
struct dim_velocity : derived_dimension<dim_velocity, metre_per_second,
exp<dim_time, -1>, exp<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:`The Downcasting Facility`.
Hopefully if [P0847]_ will land in C++23 the additional CRTP-related
template parameter will be removed from this definition.
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(std::is_same_v<dimension_unit<si::dim_length>, si::metre>);
static_assert(std::is_same_v<dimension_unit<si::dim_velocity>, si::metre_per_second>);
.. rubric:: Citations:
.. [P0847] `"Deducing this" <https://wg21.link/P0847>`_, Programming Language C++ proposal

View File

@ -0,0 +1,159 @@
.. 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:`scalar` we just have to pass
the value to the `quantity` class template explicit constructor::
quantity<si::dim_length, si::kilometre, double> d(123);
.. 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
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, Scalar Rep = double>
using length = quantity<dim_length, U, Rep>;
}
Thanks to that, the above example can be rewritten as follows::
si::length<si::kilometre> d(123);
To further simplify construction of quantities with compile-time known
values the library provides :abbr:`UDL (User Defined Literal)` s for each
:term:`unit` of every :term:`dimension`. Thanks to them the same code can
be as simple as::
using namespace si::literals;
constexpr auto d1 = 123q_km; // si::length<si::kilometre, std::int64_t>
constexpr auto d2 = 123.q_km; // si::length<si::kilometre, long double>
``123q_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.
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 si::literals;
constexpr Length auto d = 123q_km; // si::length<si::kilometre, std::int64_t>
.. note::
All instances of `quantity` class always match the `Quantity` concept.
All other regular types that are not quantities are called
:term:`scalars <scalar>` by the library and match the `Scalar` 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 si::literals;
using namespace international::literals;
constexpr Velocity auto v1 = avg_speed(220q_km, 2q_h);
constexpr Velocity auto v2 = avg_speed(140q_mi, 2q_h);
In this and all other physical units libraries such a function can be
implemented as::
constexpr si::velocity<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 Velocity 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:`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 Velocity auto v = avg_speed(220q_km, 2q_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 Velocity auto v1 = avg_speed(220.q_km, 2q_h);
constexpr si::velocity<si::metre_per_second> v2 = v1;
constexpr Velocity auto v3 = quantity_cast<si::velocity<si::metre_per_second>(v1);
.. seealso::
More information on this subject can be found in :ref:`Conversions and Casting`
chapter.

View File

@ -0,0 +1,45 @@
.. 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.
Output streams
--------------
The easiest way to print a quantity is to provide its object to the output
stream::
using namespace si::literals;
using namespace international::literals;
constexpr Velocity auto v1 = avg_speed(220.q_km, 2q_h);
constexpr Velocity auto v2 = avg_speed(140.q_mi, 2q_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 the symbol of a :term:`unit` associated with this quantity. We will learn
more about units in the :ref:`Units` chapter, but for now, it is important
to 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
Formatting the output
---------------------
Grammar:
.. productionlist::
units-format-spec: fill-and-align[opt] sign[opt] width[opt] precision[opt] units-specs[opt]
units-specs: conversion-spec
: units-specs conversion-spec
: units-specs literal-char
literal-char: any character other than '{' or '}'
conversion-spec: '%' modifier[opt] type
modifier: one of 'E', 'O'
type: one of 'n', 'q', 'Q', 't', '%'

319
docs/framework/units.rst Normal file
View File

@ -0,0 +1,319 @@
.. 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 ``10s`` is ``10`` times more than ``1s``.
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>`.
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:`The Downcasting Facility`.
Hopefully if [P0847]_ will land in C++23 the additional CRTP-related
template parameter will be removed from this definition.
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. The
fact that the `base_dimension` takes the base unit in its definition makes
it really easy to define other systems of units. 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 cgs {
struct dim_length : base_dimension<"L", si::centimetre> {};
}
The fact that both base dimensions use the same identifier ``"L"`` tells
the library that bot 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 `si::centimetre` in the `cgs::dim_length`
definition 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).
Derived Units
-------------
Derived units can be either named or unnamed.
Derived Named Units
^^^^^^^^^^^^^^^^^^^
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 defined 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,
exp<si::dim_mass, 1>,
exp<si::dim_length, 1>,
exp<si::dim_time, -1>> {}; // kg⋅m/s
struct dim_momentum : derived_dimension<dim_momentum, kilogram_metre_per_second,
exp<si::dim_length, 1>,
exp<si::dim_mass, 1>,
exp<si::dim_time, -1>> {}; // m⋅kg/s
struct dim_momentum : derived_dimension<dim_momentum, kilogram_metre_per_second,
exp<si::dim_time, -1>,
exp<si::dim_length, 1>,
exp<si::dim_mass, 1>> {}; // 1/s⋅m⋅kg
where ``kilogram_metre_per_second`` is defined as::
struct kilogram_metre_per_second : unit<kilogram_metre_per_second> {};
However, the easiest way to define momentum is just to use the
`si::velocity` derived dimension in the recipe:
.. code-block::
:emphasize-lines: 3
struct dim_momentum : derived_dimension<dim_momentum, kilogram_metre_per_second,
exp<si::dim_mass, 1>,
exp<si::dim_velocity, 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,
exp<si::dim_force, 1>,
exp<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.
Scaled Units
------------
Until now we talked mostly about
:term:`coherent units <coherent derived unit>` which are units used to
define dimensions and thus, in their system of units, have proportionality
factor/ratio equals one. However quantities of each dimension can also use
other units of measurement to describe their magnitude (numerical value).
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", no_prefix, ratio<60>, second> {};
struct hour : named_scaled_unit<hour, "h", no_prefix, ratio<60>, minute> {};
struct day : named_scaled_unit<hour, "d", no_prefix, ratio<24>, hour> {};
where `no_prefix` is a special tag type describing that the library should
not allow to define a new prefixed unit that would use this unit as a
reference ("kilohours" does not have much sense, right?). The `ratio` type
used in the definition is really similar to ``std::ratio`` but it takes
the third additional argument that defines the exponent of the ratio.
Thanks to it we can address nearly infinite scaling factors between units
and define units like:
.. code-block::
:force:
struct electronvolt : named_scaled_unit<electronvolt, "eV", prefix,
ratio<1'602'176'634, 1'000'000'000, -19>, joule> {};
..
TODO Submit a bug for above lexing problem
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 prefix : prefix_type {};
struct yocto : units::prefix<yocto, prefix, "y", ratio<1, 1, -24>> {};
struct zepto : units::prefix<zepto, prefix, "z", ratio<1, 1, -21>> {};
struct atto : units::prefix<atto, prefix, "a", ratio<1, 1, -18>> {};
struct femto : units::prefix<femto, prefix, "f", ratio<1, 1, -15>> {};
struct pico : units::prefix<pico, prefix, "p", ratio<1, 1, -12>> {};
struct nano : units::prefix<nano, prefix, "n", ratio<1, 1, -9>> {};
struct micro : units::prefix<micro, prefix, "µ", ratio<1, 1, -6>> {};
struct milli : units::prefix<milli, prefix, "m", ratio<1, 1, -3>> {};
struct centi : units::prefix<centi, prefix, "c", ratio<1, 1, -2>> {};
struct deci : units::prefix<deci, prefix, "d", ratio<1, 1, -1>> {};
struct deca : units::prefix<deca, prefix, "da", ratio<1, 1, 1>> {};
struct hecto : units::prefix<hecto, prefix, "h", ratio<1, 1, 2>> {};
struct kilo : units::prefix<kilo, prefix, "k", ratio<1, 1, 3>> {};
struct mega : units::prefix<mega, prefix, "M", ratio<1, 1, 6>> {};
struct giga : units::prefix<giga, prefix, "G", ratio<1, 1, 9>> {};
struct tera : units::prefix<tera, prefix, "T", ratio<1, 1, 12>> {};
struct peta : units::prefix<peta, prefix, "P", ratio<1, 1, 15>> {};
struct exa : units::prefix<exa, prefix, "E", ratio<1, 1, 18>> {};
struct zetta : units::prefix<zetta, prefix, "Z", ratio<1, 1, 21>> {};
struct yotta : units::prefix<yotta, prefix, "Y", ratio<1, 1, 24>> {};
}
Alternative hierarchy of prefixes is the one used in data information
domain:
.. code-block::
:force:
namespace data {
struct prefix : prefix_type {};
struct kibi : units::prefix<kibi, prefix, "Ki", ratio< 1'024>> {};
struct mebi : units::prefix<mebi, prefix, "Mi", ratio< 1'048'576>> {};
struct gibi : units::prefix<gibi, prefix, "Gi", ratio< 1'073'741'824>> {};
struct tebi : units::prefix<tebi, prefix, "Ti", ratio< 1'099'511'627'776>> {};
struct pebi : units::prefix<pebi, prefix, "Pi", ratio< 1'125'899'906'842'624>> {};
struct exbi : units::prefix<exbi, prefix, "Ei", ratio<1'152'921'504'606'846'976>> {};
}
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).
Deduced 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 "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 `deduced_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 : deduced_unit<kilometre_per_hour, dim_velocity, kilometre, hour> {};
}
Please note that this is the only unit-related class template that takes
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.
.. rubric:: Citations:
.. [P0847] `"Deducing this" <https://wg21.link/P0847>`_, Programming Language C++ proposal

4
docs/genindex.rst Normal file
View File

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

214
docs/glossary.rst Normal file
View File

@ -0,0 +1,214 @@
.. 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` 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`, in a `system of quantities`, defined in terms of the base quantities of
that system.
International System of Quantities
ISQ
- `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` 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 velocity.
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`, 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` 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`, 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`.
- A quantity value can be presented in more than one way.
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
scalar
- 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] **ISO 80000-1:2009(E) "Quantities and units — Part 1: General"** 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.

49
docs/index.rst Normal file
View File

@ -0,0 +1,49 @@
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 this ISO C++ paper: `P1935 <https://wg21.link/p1935>`_.
It is explained in this `CppCon 2019 talk <https://youtu.be/0YW6yxkdhlU>`_ (slightly dated now).
We are working towards potentially having it standardized for C++23 and are actively looking
for parties interested in field trialing the library.
.. note::
As this library targets C++23 and extensively uses C++20 features as of now it compiles correctly
only with gcc-9.1 and newer.
.. toctree::
:maxdepth: 2
:caption: Getting Started:
introduction
quick_start
usage
framework
scenarios
design
examples
faq
.. toctree::
:maxdepth: 1
:caption: Reference:
reference/concepts
reference/types
reference/functions
reference/systems
.. toctree::
:maxdepth: 1
:caption: Appendix:
glossary
genindex
CHANGELOG

47
docs/introduction.rst Normal file
View File

@ -0,0 +1,47 @@
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`.
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

62
docs/quick_start.rst Normal file
View File

@ -0,0 +1,62 @@
Quick Start
===========
Here is a small example of possible operations::
// simple numeric operations
static_assert(10q_km / 2 == 5q_km);
// unit conversions
static_assert(1q_h == 3600q_s);
static_assert(1q_km + 1q_m == 1001q_m);
// dimension conversions
static_assert(2q_m * 3q_m == 6q_m2);
static_assert(10q_km / 5q_km == 2);
static_assert(1000 / 1q_s == 1q_kHz);
static_assert(1q_km / 1q_s == 1000q_mps);
static_assert(2q_kmph * 2q_h == 4q_km);
static_assert(2q_km / 2q_kmph == 1q_h);
.. admonition:: Try it on Compiler Explorer
`Example #1 <https://godbolt.org/z/BZjWbD>`_
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/physical/si/velocity.h>
#include <units/physical/international/velocity.h>
#include <iostream>
using namespace units;
constexpr Velocity auto avg_speed(Length auto d, Time auto t)
{
return d / t;
}
int main()
{
using namespace si::literals;
Velocity auto v1 = avg_speed(220q_km, 2q_h);
Velocity auto v2 = avg_speed(si::length<international::mile>(140), si::time<si::hour>(2));
Velocity auto v3 = quantity_cast<si::metre_per_second>(v2);
Velocity auto v4 = quantity_cast<int>(v3);
std::cout << v1 << '\n'; // 110 km/h
std::cout << v2 << '\n'; // 70 mi/h
std::cout << v3 << '\n'; // 31.2928 m/s
std::cout << v4 << '\n'; // 31 m/s
}
.. admonition:: Try it on Compiler Explorer
`Example #2 <https://godbolt.org/z/_Yx6D7>`_
.. seealso::
You can find more code examples in the :ref:`Examples` chapter.

View File

@ -0,0 +1,62 @@
Concepts
========
.. namespace:: units
.. note::
All names defined in this chapter reside in the :any:`units` namespace unless specified otherwise.
.. concept:: template<typename T> PrefixType
Satisfied by all types derived from :class:`prefix_type`.
.. concept:: template<typename T> Prefix
Satisfied by all instantiations of :class:`prefix`.
.. concept:: template<typename T> Ratio
Satisfied by all instantiations of :class:`ratio`.
.. concept:: template<typename R> UnitRatio
Satisfied by all types that satisfy :expr:`Ratio<R>` and for which :expr:`R::num > 0` and :expr:`R::den > 0`.
.. concept:: template<typename T> BaseDimension
Satisfied by all dimension types derived from instantiation of :class:`base_dimension`.
.. concept:: template<typename T> Exponent
Satisfied by all instantiations of :class:`exp`.
.. concept:: template<typename T> DerivedDimension
Satisfied by all dimension types derived from instantiation of :class:`detail::derived_dimension_base`.
.. concept:: template<typename T> Dimension
Satisfied by all dimension types for which either :expr:`BaseDimension<T>` or :expr:`DerivedDimension<T>` is ``true``.
.. concept:: template<typename T> Unit
Satisfied by all unit types derived from instantiation of :class:`scaled_unit`.
.. concept:: template<typename U, typename D> UnitOf
Satisfied by all unit types that satisfy :expr:`Unit<U>`, :expr:`Dimension<D>`, and for which
:expr:`U::reference` and :expr:`dimension_unit<D>::reference` denote the same unit type.
.. concept:: template<typename T> Quantity
Satisfied by all instantiations of :class:`quantity`.
.. concept:: template<typename T> WrappedQuantity
Satisfied by all wrapper types that satisfy :expr:`Quantity<typename T::value_type>` recursively
(i.e. :expr:`std::optional<si::length<si::metre>>`).
.. concept:: template<typename T> Scalar
Satisfied by types that satisfy :expr:`(!Quantity<T>) && (!WrappedQuantity<T>) && std::regular<T>`.

View File

@ -0,0 +1,15 @@
.. note::
All names defined in this chapter reside in the :any:`units` namespace unless specified otherwise.
Functions
=========
.. doxygenfunction:: quantity_cast
Metafunctions
=============
.. doxygentypedef:: dimension_unit

View File

@ -0,0 +1,32 @@
.. note::
All names defined in this chapter reside in the :any:`units` namespace unless specified otherwise.
Systems
=======
SI
--
..
doxygennamespace:: units::si
:members:
:undoc-members:
:outline:
File
----
..
doxygenfile:: si/length.h
Group
-----
..
doxygengroup:: si_length
:content-only:
:members:
:undoc-members:
:outline:

51
docs/reference/types.rst Normal file
View File

@ -0,0 +1,51 @@
.. note::
All names defined in this chapter reside in the :any:`units` namespace unless specified otherwise.
Types
=====
Quantity
--------
.. doxygenclass:: units::quantity
:members:
..
:undoc-members:
Dimension
---------
.. doxygenstruct:: units::base_dimension
:members:
.. doxygenstruct:: units::derived_dimension
:members:
Unit
----
.. doxygenstruct:: units::scaled_unit
:members:
.. doxygenstruct:: units::unit
:members:
.. doxygenstruct:: units::named_unit
:members:
.. doxygenstruct:: units::named_scaled_unit
:members:
.. doxygenstruct:: units::prefixed_unit
:members:
.. doxygenstruct:: units::deduced_unit
:members:
Ratio
-----
.. doxygenstruct:: units::ratio
:members:

3
docs/requirements.txt Normal file
View File

@ -0,0 +1,3 @@
sphinx
recommonmark
breathe

15
docs/scenarios.rst Normal file
View File

@ -0,0 +1,15 @@
Scenarios
=========
.. note::
For brevity all the code examples in this documentation will assume::
using namespace units;
.. toctree::
:maxdepth: 2
scenarios/unknown_units_and_dimensions
scenarios/legacy_interfaces
scenarios/extensions

View File

@ -0,0 +1,19 @@
.. namespace:: units
Extending the library
=====================
Custom Units
------------
Custom Dimensions
-----------------
Custom Base Dimensions
^^^^^^^^^^^^^^^^^^^^^^
Custom Derived Dimensions
^^^^^^^^^^^^^^^^^^^^^^^^^
Custom Systems
--------------

View File

@ -0,0 +1,41 @@
.. namespace:: units
Working with Legacy Interfaces
==============================
In case we are working with a legacy/unsafe interface we may be forced to
extract a :term:`value of a quantity` with :func:`quantity::count()` and
pass it to the library's output:
.. code-block::
:caption: legacy.h
namespace legacy {
void print_eta(double speed_in_mps);
} // namespace legacy
.. code-block::
#include "legacy.h"
#include <units/physical/si/velocity.h>
using namespace units;
constexpr Velocity auto avg_speed(Length auto d, Time auto t)
{
return d / t;
}
void print_eta(Length auto d, Time auto t)
{
Velocity auto v = avg_speed(d, t);
legacy::print_eta(quantity_cast<si::metre_per_second>(v).count());
}
.. important::
When dealing with a quantity of an unknown ``auto`` type please remember
to always use `quantity_cast` to cast it to a desired unit before calling
`quantity::count()` and passing the raw value to the legacy/unsafe interface.

View File

@ -0,0 +1,9 @@
.. namespace:: units
Working with Unknown Units and Dimensions
=========================================
- what is an unknown unit?
- what is an unknown dimension?
- temporary result
- casting to the coherent unit

View File

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

233
docs/usage.rst Normal file
View File

@ -0,0 +1,233 @@
Usage
=====
.. note::
As this library targets C++23 and extensively uses C++20 features as of now it compiles correctly
only with gcc-9.1 and newer.
Repository structure and dependencies
-------------------------------------
This repository contains three independent CMake-based projects:
- *./src*
- header-only project containing whole **mp-units** library
- when C++20 support will be fully supported by C++ compilers this library will have
no external dependencies but until then it depends on
`range-v3 <https://github.com/ericniebler/range-v3>`_ (only for gcc versions < 10.0)
and `{fmt} <https://github.com/fmtlib/fmt>`_ libraries.
- *.*
- 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/linear_algebra/code>`_
library based on proposal `P1385 <https://wg21.link/P1385>`_ used in some examples
and tests.
- `Doxygen <http://www.doxygen.nl>`_ to extract C++ entities information from the source
code.
- `Sphinx <https://www.sphinx-doc.org>`_ to build the documentation.
- `Sphinx recommonmark <https://recommonmark.readthedocs.io>`_.
- `Breathe <https://breathe.readthedocs.io/>`_ as a bridge between the Sphinx and Doxygen
documentation systems.
- *./test_package*
- library installation and Conan package verification
.. note::
Please note that **mp-units** repository also depends on a git submodule in the
*./cmake/common* subdirectory providing some common CMake utilities.
Obtaining Dependencies
----------------------
This library assumes that most of the dependencies will be provided by the
`Conan Package Manager <https://conan.io/>`_. In case you would like to obtain needed
dependencies by other means some modifications to library's CMake files will be needed.
The rest of the dependencies are provided by :command:`python3-pip`.
Conan quick intro
^^^^^^^^^^^^^^^^^
In case you are not familiar with Conan, to install it (or upgrade) just do:
.. code-block:: shell
pip3 install -U conan
After that you might need to add a custom profile file for your development environment
in *~/.conan/profile* directory. An example profile can look as follows:
.. code-block:: ini
:emphasize-lines: 8
[settings]
os=Linux
os_build=Linux
arch=x86_64
arch_build=x86_64
compiler=gcc
compiler.version=9
compiler.cppstd=20
compiler.libcxx=libstdc++11
build_type=Release
[options]
[build_requires]
[env]
CC=/usr/bin/gcc-9
CXX=/usr/bin/g++-9
.. tip::
Please note that **mp-units** library requires C++20 to be set either in a Conan profile or forced
via Conan command line. If you do the former, you will not need to provide ``-s compiler.cppstd=20``
every time your rune a Conan command line (as it is suggested below).
Non-standard Conan remotes
^^^^^^^^^^^^^^^^^^^^^^^^^^
Add the following remotes to your local Conan instance:
.. code-block:: shell
conan remote add conan-mpusz https://api.bintray.com/conan/mpusz/conan-mpusz
conan remote add bincrafters https://api.bintray.com/conan/bincrafters/public-conan
conan remote add linear-algebra https://api.bintray.com/conan/twonington/public-conan
.. note::
The last two remotes are needed only if you plan to build all of the code and documentation
in **mp-units** repository.
Build options
-------------
Environment variables
^^^^^^^^^^^^^^^^^^^^^
.. envvar:: CONAN_RUN_TESTS
**Defaulted to**: Not defined (``True``/``False`` if defined)
Enables compilation of all the source code (tests and examples) and building the documentation.
To support that it requires some additional Conan build dependencies described in
`Repository structure and dependencies`_.
It also runs unit tests during Conan build.
Building, Installation, and Reuse
---------------------------------
There are a few different ways of installing/reusing **mp-units** in your project.
Copy
^^^^
As **mp-units** is a C++ header-only library you can simply copy *src/include* directory to
your source tree and use it as regular header files.
CMake + Conan
^^^^^^^^^^^^^
To use **mp-units** as a CMake imported library the following steps may be performed:
1. Clone the repository together with its submodules:
.. code-block:: shell
git clone --recurse-submodules https://github.com/mpusz/units.git
or in case it is already cloned without submodules, initialize, fetch, and checkout them with:
.. code-block:: shell
git submodule update --init
2. Create Conan configuration file (either *conanfile.txt* or *conanfile.py*) in your
project's top-level directory and add **mp-units** as a dependency to your Conan configuration
file.
- for example to use **mp-units** testing/prerelease version ``0.5.0`` in case of *conanfile.txt*
it is enough for it to just contain the following lines:
.. code-block:: ini
[requires]
mp-units/0.5.0@mpusz/testing
3. Import Conan dependencies definitions to the beginning of your top-level *CMakeLists.txt*
file in your project:
.. code-block:: cmake
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup(TARGETS)
4. Link your CMake target with **mp-units**:
.. code-block:: cmake
target_link_libraries(<your_target> PUBLIC|PRIVATE|INTERFACE CONAN_PKG::mp-units)
5. Download and install Conan dependencies before running CMake configuration step:
.. code-block:: shell
cd build
conan install .. -pr <your_conan_profile> -s compiler.cppstd=20 -b=outdated -u
6. Configure your CMake project as usual.
Full **mp-units** build, unit testing, and documentation generation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In case you would like to build all the source code (with unit tests and examples) and documentation
in **mp-units** repository, you should use the *CMakeLists.txt* from the top-level directory,
obtain Python dependencies, and run Conan with :envvar:`CONAN_RUN_TESTS` = ``True``:
.. code-block:: shell
git clone --recurse-submodules https://github.com/mpusz/units.git && cd units
pip3 install -r docs/requirements.txt
mkdir build && cd build
conan install .. -pr <your_conan_profile> -s compiler.cppstd=20 -e CONAN_RUN_TESTS=True -b outdated
cmake .. -DCMAKE_BUILD_TYPE=Release
cmake --build .
ctest
The above will download and install all of the dependencies needed for the development of the library,
build all of the source code and documentation, and run unit tests.
Packaging
---------
To test CMake installation and Conan packaging or create a Conan package run:
.. code-block:: shell
git clone --recurse-submodules https://github.com/mpusz/units.git && cd units
pip3 install -r docs/requirements.txt
conan create . <username>/<channel> -pr <your_conan_profile> -s compiler.cppstd=20 -e CONAN_RUN_TESTS=True -b outdated
The above will create a Conan package and run tests provided in *./test_package* directory.
Uploading **mp-units** package to the Conan server
--------------------------------------------------
.. code-block:: shell
conan upload -r <remote-name> --all mp-units/0.5.0@<user>/<channel>