forked from mpusz/mp-units
Sphinx-based documentation added
This commit is contained in:
1
docs/CHANGELOG.md
Symbolic link
1
docs/CHANGELOG.md
Symbolic link
@@ -0,0 +1 @@
|
||||
../CHANGELOG.md
|
||||
104
docs/CMakeLists.txt
Normal file
104
docs/CMakeLists.txt
Normal 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})
|
||||
965
docs/DESIGN.md
Normal file
965
docs/DESIGN.md
Normal file
@@ -0,0 +1,965 @@
|
||||
# `mp-units` - Design Overview
|
||||
|
||||
|
||||
## 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);
|
||||
```
|
||||
|
||||
|
||||
## 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
|
||||
|
||||
|
||||
## Basic Concepts
|
||||
|
||||
The most important concepts in the library are `Unit`, `Dimension`, and `Quantity`:
|
||||
|
||||

|
||||
|
||||
`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_unit` 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.
|
||||
|
||||
|
||||
## `Unit`
|
||||
|
||||
All units are represented in the framework by a `scaled_unit` class template:
|
||||
|
||||
```cpp
|
||||
template<UnitRatio R, typename U>
|
||||
struct scaled_unit : downcast_base<scaled_unit<R, U>> {
|
||||
using ratio = R;
|
||||
using reference = U;
|
||||
};
|
||||
```
|
||||
|
||||
where:
|
||||
|
||||
```cpp
|
||||
template<typename R>
|
||||
concept UnitRatio = Ratio<R> && R::num > 0 && R::den > 0; // double negatives not allowed
|
||||
```
|
||||
|
||||
and `Ratio` is satisfied by any instantiation of `units::ratio<Num, Den, Exp>`.
|
||||
|
||||
The `scaled_unit` type is a framework's private type and the user should never instantiate it directly.
|
||||
The public user interface to create units consists of:
|
||||
|
||||

|
||||
|
||||
All below class templates indirectly derive from a `scaled_unit` class template and satisfy a
|
||||
`Unit` concept:
|
||||
- `unit`
|
||||
- Defines a new unnamed, in most cases coherent derived unit of a specific derived
|
||||
dimension and it should be passed in this dimension's definition.
|
||||
- `named_unit`
|
||||
- Defines a named, in most cases base or coherent unit that is then passed to a dimension's
|
||||
definition.
|
||||
- A named unit may be used by other units defined with the prefix of the same type, unless
|
||||
`no_prefix` is provided for `PrefixType` template parameter (in such a case it is impossible
|
||||
to define a prefixed unit based on this one).
|
||||
- `named_scaled_unit`
|
||||
- Defines a new named unit that is a scaled version of another unit.
|
||||
- Such unit can be used by other units defined with the prefix of the same type, unless
|
||||
`no_prefix` is provided for `PrefixType` template parameter (in such a case it is impossible
|
||||
to define a prefixed unit based on this one).
|
||||
- `prefixed_unit`
|
||||
- Defines a new unit that is a scaled version of another unit by the provided prefix.
|
||||
- It is only possible to create such a unit if the given prefix type matches the one defined
|
||||
in a reference unit.
|
||||
- `deduced_unit`
|
||||
- Defines a new unit with a deduced ratio and symbol based on the recipe from the provided
|
||||
derived dimension.
|
||||
- The number and order of provided units should match the recipe of the derived dimension.
|
||||
- All of the units provided should also be a named ones so it is possible to create a deduced
|
||||
symbol text.
|
||||
|
||||
Some of the above types depend on `PrefixType` and `no_prefix`. `PrefixType` is a concept that
|
||||
is defined as:
|
||||
|
||||
```cpp
|
||||
template<typename T>
|
||||
concept PrefixType = std::derived_from<T, prefix_type>;
|
||||
```
|
||||
|
||||
where `prefix_type` is just an empty tag type used to identify the beginning of prefix types
|
||||
hierarchy and `no_prefix` is one of its children:
|
||||
|
||||
```cpp
|
||||
struct prefix_type {};
|
||||
struct no_prefix : prefix_type {};
|
||||
```
|
||||
|
||||
Concrete prefix derives from a `prefix` class template:
|
||||
|
||||
```cpp
|
||||
template<typename Child, PrefixType PT, basic_fixed_string Symbol, Ratio R>
|
||||
requires (!std::same_as<PT, no_prefix>)
|
||||
struct prefix;
|
||||
```
|
||||
|
||||
You could notice that both units and above `prefix` class template take `Child` as a first
|
||||
template parameter. `mp-units` library heavily relies on CRTP (Curiously Recurring Template
|
||||
Parameter) idiom to provide the best user experience in terms of readability of compilation
|
||||
errors and during debugging. It is possible thanks to the downcasting facility described later
|
||||
in the design documentation.
|
||||
|
||||
Coming back to units, here are a few examples of unit definitions:
|
||||
|
||||
```cpp
|
||||
namespace units::si {
|
||||
|
||||
// prefixes
|
||||
struct prefix : prefix_type {};
|
||||
struct centi : units::prefix<centi, prefix, "c", ratio<1, 1, -2>> {};
|
||||
struct kilo : units::prefix<kilo, prefix, "k", ratio<1, 1, 3>> {};
|
||||
|
||||
// length
|
||||
struct metre : named_unit<metre, "m", prefix> {};
|
||||
struct centimetre : prefixed_unit<centimetre, centi, metre> {};
|
||||
struct kilometre : prefixed_unit<kilometre, kilo, metre> {};
|
||||
|
||||
// time
|
||||
struct second : named_unit<second, "s", prefix> {};
|
||||
struct hour : named_scaled_unit<hour, "h", no_prefix, ratio<3600>, second> {};
|
||||
|
||||
// velocity
|
||||
struct metre_per_second : unit<metre_per_second> {};
|
||||
struct kilometre_per_hour : deduced_unit<kilometre_per_hour, dim_velocity, kilometre, hour> {};
|
||||
|
||||
}
|
||||
|
||||
namespace units::us {
|
||||
|
||||
// length
|
||||
struct yard : named_scaled_unit<yard, "yd", no_prefix, ratio<9'144, 10'000>, si::metre> {};
|
||||
struct mile : named_scaled_unit<mile, "mi", no_prefix, ratio<1'760>, yard> {};
|
||||
|
||||
// velocity
|
||||
struct mile_per_hour : deduced_unit<mile_per_hour, si::dim_velocity, mile, si::hour> {};
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Please note that thanks to C++20 features we are able to provide all information about the unit
|
||||
(including text output) in a single line of its type definition. There is no need to specialize
|
||||
additional type traits or use preprocessor macros.
|
||||
|
||||
|
||||
## `Dimension`
|
||||
|
||||
`Dimension` is either a `BaseDimension` or a `DerivedDimension`:
|
||||
|
||||
```cpp
|
||||
template<typename T>
|
||||
concept Dimension = BaseDimension<T> || DerivedDimension<T>;
|
||||
```
|
||||
|
||||
### `BaseDimension`
|
||||
|
||||
According to ISO 80000 a base quantity is a 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 within that subset. They are referred to as being mutually independent since a
|
||||
base quantity cannot be expressed as a product of powers of the other base quantities. Base unit
|
||||
is a measurement unit that is adopted by convention for a base quantity in a specific system of
|
||||
units.
|
||||
|
||||
`base_dimension` represents a dimension of a base quantity and is identified with a pair of
|
||||
an unique compile-time text describing the dimension symbol and a base unit adopted for this
|
||||
dimension:
|
||||
|
||||
```cpp
|
||||
template<basic_fixed_string Symbol, Unit U>
|
||||
requires U::is_named
|
||||
struct base_dimension {
|
||||
static constexpr auto symbol = Symbol;
|
||||
using base_unit = U;
|
||||
};
|
||||
```
|
||||
|
||||
Pair of symbol and unit template parameters form an unique identifier of the base dimension.
|
||||
These identifiers provide total ordering of exponents of base dimensions in a derived dimension.
|
||||
|
||||
The SI physical units system defines 7 base dimensions:
|
||||
|
||||
```cpp
|
||||
namespace units::si {
|
||||
|
||||
struct dim_length : base_dimension<"L", metre> {};
|
||||
struct dim_mass : base_dimension<"M", kilogram> {};
|
||||
struct dim_time : base_dimension<"T", second> {};
|
||||
struct dim_electric_current : base_dimension<"I", ampere> {};
|
||||
struct dim_thermodynamic_temperature : base_dimension<"Θ", kelvin> {};
|
||||
struct dim_substance : base_dimension<"N", mole> {};
|
||||
struct dim_luminous_intensity : base_dimension<"J", candela> {};
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
All other derived quantities of SI are composed from those.
|
||||
|
||||
There are two reasons why a `base_dimension` gets a unit as its template parameter. First, the
|
||||
base unit is needed for the text output of unnamed derived units. Second, there is more than
|
||||
one system of physical units. For example CGS definitions look as follows:
|
||||
|
||||
```cpp
|
||||
namespace units::cgs {
|
||||
|
||||
using si::centimetre;
|
||||
using si::gram;
|
||||
using si::second;
|
||||
|
||||
struct dim_length : base_dimension<"L", centimetre> {};
|
||||
struct dim_mass : base_dimension<"M", gram> {};
|
||||
using si::dim_time;
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Equivalent base dimensions in different systems have the same symbol identifier and get units
|
||||
from the same hierarchy (with the same reference in `scaled_unit`). Thanks to that we have
|
||||
the ability to explicitly cast quantities of the same dimension from different systems or
|
||||
even mix them in one `derived_dimension` definition.
|
||||
|
||||
|
||||
### `DerivedDimension`
|
||||
|
||||
According to ISO 80000 a derived quantity is a quantity, in a system of quantities, defined in
|
||||
terms of the base quantities of that system. Dimension of such quantity is an expression of the
|
||||
dependence of a quantity on the base quantities of a system of quantities as a product of
|
||||
powers of factors corresponding to the base quantities, 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.
|
||||
|
||||
A derived dimension used internally in a library framework is implemented as a type-list like
|
||||
type that stores an ordered list of exponents of one or more base dimensions:
|
||||
|
||||
```cpp
|
||||
namespace detail {
|
||||
|
||||
template<Exponent E, Exponent... ERest>
|
||||
requires (BaseDimension<typename E::dimension> && ... && BaseDimension<typename ERest::dimension>)
|
||||
struct derived_dimension_base;
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
A derived dimension can be formed from multiple exponents (i.e. velocity is represented as
|
||||
`exp<L, 1>, exp<T, -1>`). It is also possible to form a derived dimension with only one exponent
|
||||
(i.e. frequency is represented as just `exp<T, -1>`).
|
||||
|
||||
Exponents are implemented with `exp` class template that provides an information about a single
|
||||
dimension and its (possibly fractional) exponent in a derived dimension.
|
||||
|
||||
```cpp
|
||||
template<Dimension Dim, std::intmax_t Num, std::intmax_t Den = 1>
|
||||
struct exp {
|
||||
using dimension = Dim;
|
||||
static constexpr std::intmax_t num = Num;
|
||||
static constexpr std::intmax_t den = Den;
|
||||
};
|
||||
```
|
||||
|
||||
In order to be able to perform computations on an arbitrary set of exponents,
|
||||
`derived_dimension_base` class template have to obey the following rules:
|
||||
- it contains only base dimensions in the list of exponents,
|
||||
- base dimensions are not repeated in a list (the exponent of each base dimension is provided
|
||||
at most once),
|
||||
- exponents of base dimensions are consistently ordered,
|
||||
- in case the numerator of the exponent equals zero such base dimension is erased from the list.
|
||||
|
||||
Above is needed for the framework to provide dimensional analysis. However, sometimes it is
|
||||
useful to define derived units in terms of other derived units. To support this both a base
|
||||
dimension and a derived dimension can be provided to `exp` class template.
|
||||
|
||||
As it was stated above `derived_dimension_base` is a private utility of the framework. In order
|
||||
to define a new derived dimension the user has to instantiate the following class template:
|
||||
|
||||
```cpp
|
||||
template<typename Child, Unit U, Exponent E, Exponent... ERest>
|
||||
struct derived_dimension : downcast_child<Child, typename detail::make_dimension<E, ERest...>> {
|
||||
using recipe = exp_list<E, ERest...>;
|
||||
using coherent_unit = U;
|
||||
using base_units_ratio = /* see below */;
|
||||
};
|
||||
```
|
||||
|
||||
There are a few important differences between `detail::derived_dimension_base` and
|
||||
`derived_dimension`. First, the latter one gets the coherent unit of the derived dimension.
|
||||
|
||||
According to ISO 80000 a coherent unit is a unit that, for a given system of quantities and for
|
||||
a chosen set of base units, is a product of powers of base units with no other proportionality
|
||||
factor than one.
|
||||
|
||||
The other difference is that `derived_dimension` allows to provide other derived dimensions in
|
||||
the list of its exponents. This is called a "recipe" of the dimension and among others is used
|
||||
to print unnamed coherent units of this dimension.
|
||||
|
||||
In case a derived dimension appears on the list of exponents, such derived dimension will be
|
||||
unpacked, sorted, and consolidated by a `detail::make_dimension` helper to form a valid list
|
||||
of exponents of only base dimensions later provided to `detail::derived_dimension_base`.
|
||||
|
||||
Sometimes units of equivalent quantities in different systems of units do not share the same
|
||||
reference so they cannot be easily converted to each other. An example can be a pressure for
|
||||
which a coherent unit in SI is pascal and in CGS barye. Those two units are not directly
|
||||
related with each other with some ratio. As they both are coherent units of their dimensions,
|
||||
the ratio between them is directly determined by the ratios of base units defined in base
|
||||
dimensions end their exponents in the derived dimension recipe. To provide interoperability of
|
||||
such quantities of different systems `base_units_ratio` is being used. The result of the
|
||||
division of two `base_units_ratio` of two quantities of equivalent dimensions in two different
|
||||
systems gives a ratio between their coherent units. Alternatively, the user would always have to
|
||||
directly define a barye in terms of pascal or vice versa.
|
||||
|
||||
Below are a few examples of derived dimension definitions:
|
||||
|
||||
```cpp
|
||||
namespace units::si {
|
||||
|
||||
struct dim_velocity : derived_dimension<dim_velocity, metre_per_second,
|
||||
exp<dim_length, 1>, exp<dim_time, -1>> {};
|
||||
|
||||
struct dim_acceleration : derived_dimension<dim_acceleration, metre_per_second_sq,
|
||||
exp<dim_length, 1>, exp<dim_time, -2>> {};
|
||||
|
||||
struct dim_force : derived_dimension<dim_force, newton,
|
||||
exp<dim_mass, 1>, exp<dim_acceleration, 1>> {};
|
||||
|
||||
struct dim_energy : derived_dimension<dim_energy, joule,
|
||||
exp<dim_force, 1>, exp<dim_length, 1>> {};
|
||||
|
||||
struct dim_power : derived_dimension<dim_power, watt,
|
||||
exp<dim_energy, 1>, exp<dim_time, -1>> {};
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
If as a result of dimensional computation the library framework will generate a derived
|
||||
dimension that was not predefined by the user than the instance of
|
||||
`unknown_dimension<Exponent...>`. The coherent unit of such an unknown dimension is
|
||||
`scaled_unit<ratio<1>, unknown_coherent_unit>`.
|
||||
|
||||
|
||||
## `Quantity`
|
||||
|
||||
`quantity` is a class template that expresses the quantity/amount of a specific dimension
|
||||
expressed in a specific unit of that dimension:
|
||||
|
||||
```cpp
|
||||
template<Dimension D, UnitOf<D> U, Scalar Rep = double>
|
||||
class quantity
|
||||
```
|
||||
|
||||
`quantity` provides a similar interface to `std::chrono::duration`. The difference is that it
|
||||
uses `double` as a default representation and has a few additional member types and
|
||||
functions as below:
|
||||
|
||||
```cpp
|
||||
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` class:
|
||||
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.
|
||||
|
||||
To simplify writing efficient generic code quantities of each dimension have associated:
|
||||
1. Concept (i.e. `units::Length`) that matches a length dimension of any physical systems.
|
||||
2. Per-system quantity alias (i.e. `units::si::length<Unit, Rep>` for
|
||||
`units::quantity<units::si::dim_length, Unit, Rep>`).
|
||||
|
||||
Also, to help instantiate quantities with compile-time known values every unit in the library
|
||||
has an associated UDL. For example:
|
||||
|
||||
```cpp
|
||||
namespace si::inline literals {
|
||||
|
||||
// m
|
||||
constexpr auto operator"" q_m(unsigned long long l) { return length<metre, std::int64_t>(l); }
|
||||
constexpr auto operator"" q_m(long double l) { return length<metre, long double>(l); }
|
||||
|
||||
// km
|
||||
constexpr auto operator"" q_km(unsigned long long l) { return length<kilometre, std::int64_t>(l); }
|
||||
constexpr auto operator"" q_km(long double l) { return length<kilometre, long double>(l); }
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### `quantity_cast`
|
||||
|
||||
To explicitly force truncating conversions `quantity_cast` function is provided which is a direct
|
||||
counterpart of `std::chrono::duration_cast`. As a template argument user can provide here either
|
||||
a `quantity` type or only its template parameters (`Dimension`, `Unit`, or `Rep`):
|
||||
|
||||
```cpp
|
||||
template<Quantity To, typename D, typename U, typename Rep>
|
||||
requires QuantityOf<To, D> &&
|
||||
detail::basic_arithmetic<std::common_type_t<typename To::rep, Rep, intmax_t>>
|
||||
[[nodiscard]] constexpr auto quantity_cast(const quantity<D, U, Rep>& q);
|
||||
|
||||
template<Dimension ToD, typename D, typename U, typename Rep>
|
||||
requires equivalent_dim<ToD, D>
|
||||
[[nodiscard]] constexpr auto quantity_cast(const quantity<D, U, Rep>& q);
|
||||
|
||||
template<Unit ToU, typename D, typename U, typename Rep>
|
||||
requires UnitOf<ToU, D>
|
||||
[[nodiscard]] constexpr auto quantity_cast(const quantity<D, U, Rep>& q);
|
||||
|
||||
template<Scalar ToRep, typename D, typename U, typename Rep>
|
||||
requires detail::basic_arithmetic<std::common_type_t<ToRep, Rep, intmax_t>>
|
||||
[[nodiscard]] constexpr auto quantity_cast(const quantity<D, U, Rep>& q);
|
||||
```
|
||||
|
||||
## Text output
|
||||
|
||||
### Unit Symbol
|
||||
|
||||
The library tries its best to print a correct unit of the quantity. This is why it performs
|
||||
a series of checks:
|
||||
1. If the user predefined a unit with a `named_XXX_unit` class templates, the symbol provided
|
||||
by the user will be used (i.e. `60 W`).
|
||||
2. If a unit was created with a `deduced_unit` class template, the symbol of deduced unit is
|
||||
printed (i.e. `70 km/h`).
|
||||
3. Otherwise, the library tries to print a prefix and symbol of an unknown unit for this derived
|
||||
dimension:
|
||||
- prefix:
|
||||
- if ratio of the scaled unit is `1`, than no prefix is being printed,
|
||||
- otherwise, if `PrefixType` template parameter of a reference unit is different than
|
||||
`no_prefix`, and if the ratio of scaled unit matches the ratio of a prefix of a specified
|
||||
type, than the symbol of this prefix will be used,
|
||||
- otherwise, non-standard ratio (i.e. `2 [60]Hz`) will be printed.
|
||||
- symbol:
|
||||
- if a reference unit has a user-predefined or deduced symbol, than this symbol it is being
|
||||
printed,
|
||||
- otherwise, the symbol is constructed from names and exponents of base dimensions
|
||||
(i.e. `2 m/kg^2`).
|
||||
|
||||
|
||||
### `operator<<`
|
||||
|
||||
`quantity::operator<<()` provides only a basic support to print a quantity. It prints its count
|
||||
and a symbol separated with one space character.
|
||||
|
||||
|
||||
### Text Formatting
|
||||
|
||||
`mp-units` supports new C++20 formatting facility (currently provided as a dependency on
|
||||
[`fmt`](https://github.com/fmtlib/fmt) library). `parse()` member functions of
|
||||
`fmt::formatter<units::quantity<Dimension, Unit, Rep>, CharT>` class template partial
|
||||
specialization interprets the format specification as a `units-format-spec` according to the
|
||||
following syntax:
|
||||
|
||||
```text
|
||||
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 %
|
||||
```
|
||||
|
||||
The productions `fill-and-align`, `sign`, `width`, and `precision` are described in
|
||||
[Format string](https://wg21.link/format.string.std) chapter of the C++ standard. Giving a
|
||||
`precision` specification in the `units-format-spec` is valid only for `units::quantity` types
|
||||
where the representation type `Rep` is a floating-point type. For all other `Rep` types, an
|
||||
exception of type `format_error` is thrown if the `units-format-spec` contains a precision
|
||||
specification. An `format_error` is also thrown if `sign` is provided with a `conversion-spec`
|
||||
to print quantity unit but not its value.
|
||||
|
||||
Each conversion specifier `conversion-spec` is replaced by appropriate characters as described
|
||||
in the following table:
|
||||
|
||||
| Specifier | Replacement |
|
||||
|:---------:|---------------------------------------------------------------|
|
||||
| `%n` | A new-line character |
|
||||
| `%q` | The quantity’s unit symbol |
|
||||
| `%Q` | The quantity’s numeric value (as if extracted via `.count()`) |
|
||||
| `%t` | A horizontal-tab character |
|
||||
| `%%` | A `%` character |
|
||||
|
||||
If the `units-specs` is omitted, the `quantity` object is formatted as if by streaming it to
|
||||
`std::ostringstream os` and copying `os.str()` through the output iterator of the context with
|
||||
additional padding and adjustments as specified by the format specifiers.
|
||||
|
||||
```cpp
|
||||
std::string s = fmt::format("{:=>12}", 120q_kmph); // value of s is "====120 km/h"
|
||||
```
|
||||
|
||||
|
||||
## Improving user's experience
|
||||
|
||||
Most of the important design decisions in the library are dictated by the requirement of
|
||||
providing the best user experience as possible.
|
||||
|
||||
Most of C++ libraries in the world use template aliases to provide a friendly name for a
|
||||
developer. Unfortunately, such aliases are quickly lost in a compilation process and as a
|
||||
result the potential error log contains a huge source type rather than a short alias for it.
|
||||
The same can be observed during debugging of a code using template aliases.
|
||||
|
||||
Let's assume that we want to provide a user friendly name for a capacitance derived dimension.
|
||||
Other libraries will do it in the following way:
|
||||
|
||||
```cpp
|
||||
using dim_capacitance = detail::derived_dimension_base<exp<si::dim_electric_current, 2>,
|
||||
exp<si::dim_length, -2>,
|
||||
exp<si::dim_mass, -1>,
|
||||
exp<si::dim_time, 4>>;
|
||||
```
|
||||
|
||||
The above solution does provide a good developer's experience but a really poor one for the end
|
||||
user. If we will get a compilation error message containing `dim_capacitance` in most cases
|
||||
the compiler will print the following type instead of the alias:
|
||||
|
||||
```text
|
||||
units::detail::derived_dimension_base<units::exp<units::si::dim_electric_current, 2, 1>,
|
||||
units::exp<units::si::dim_length, -2, 1>, units::exp<units::si::dim_mass, -1, 1>,
|
||||
units::exp<units::si::dim_time, 4, 1> >
|
||||
```
|
||||
|
||||
You can notice that even this long syntax was carefully selected to provide quite good user
|
||||
experience (some other units libraries produce a type that cannot easily fit on one slide)
|
||||
but it is not questionable less readable than just `dim_capacitance`.
|
||||
|
||||
NOTE: To better understand how the framework works and not clutter the text and graphs with
|
||||
long types in the following examples we will switch from `dim_capacitance` to `dim_area`.
|
||||
The latter one has much shorter definition but the end result for both will be exactly the same.
|
||||
User-friendly, short name printed by the compiler and the debugger.
|
||||
|
||||
To fix it we have to provide a strong type. As we do not have opaque/strong typedefs
|
||||
in the language we have to use inheritance:
|
||||
|
||||

|
||||
|
||||
This gives us a nice looking strong type but does not solve the problem of how to switch from
|
||||
a long instantiation of a `derived_dimension_base` class template that was generated by the
|
||||
framework as a result of dimensional calculation to a child class assigned by the user for this
|
||||
instantiation.
|
||||
|
||||
### Downcasting facility
|
||||
|
||||
To support this `mp-units` library introduces a new downcasting facility implemented fully as
|
||||
a library feature. It creates 1-to-1 link between a long class template instantiation and a
|
||||
strong type provided by the user. This means that only one child class can be created for a
|
||||
specific base class template instantiation.
|
||||
|
||||
Downcasting facility is provided by injecting two classes into our hierarchy:
|
||||
|
||||

|
||||
|
||||
In the above example `dim_area` is a downcasting target (child class) and a specific
|
||||
`detail::derived_dimension` class template instantiation is a downcasting source (base class).
|
||||
|
||||
```cpp
|
||||
template<typename BaseType>
|
||||
struct downcast_base {
|
||||
using downcast_base_type = BaseType;
|
||||
friend auto downcast_guide(downcast_base); // declaration only (no implementation)
|
||||
};
|
||||
```
|
||||
|
||||
`units::downcast_base` is a class that implements CRTP idiom, marks the base of downcasting
|
||||
facility with a `downcast_base_type` member type, and provides a declaration of downcasting ADL
|
||||
friendly (Hidden Friend) entry point member function `downcast_guide`. An important design point
|
||||
is that this function does not return any specific type in its declaration. This non-member
|
||||
function is going to be defined in a child class template `downcast_child` and will return a
|
||||
target type of the downcasting operation there.
|
||||
|
||||
```cpp
|
||||
template<typename T>
|
||||
concept Downcastable =
|
||||
requires {
|
||||
typename T::downcast_base_type;
|
||||
} &&
|
||||
std::derived_from<T, downcast_base<typename T::downcast_base_type>>;
|
||||
```
|
||||
|
||||
`units::Downcastable` is a concepts that verifies if a type implements and can be used in a
|
||||
downcasting facility.
|
||||
|
||||
```cpp
|
||||
template<typename Target, Downcastable T>
|
||||
struct downcast_child : T {
|
||||
friend auto downcast_guide(typename downcast_child::downcast_base) { return Target(); }
|
||||
};
|
||||
```
|
||||
|
||||
`units::downcast_child` is another CRTP class template that provides the implementation of a
|
||||
non-member friend function of the `downcast_base` class template which defines the target
|
||||
type of a downcasting operation.
|
||||
|
||||
With such CRTP types the only thing the user has to do to register a new type to the downcasting
|
||||
facility is to publicly derive from one of those CRTP types and provide its new child type as
|
||||
the first template parameter of the CRTP type.
|
||||
|
||||
Above types are used to define base and target of a downcasting operation. To perform the actual
|
||||
downcasting operation a dedicated template alias is provided:
|
||||
|
||||
```cpp
|
||||
template<Downcastable T>
|
||||
using downcast = decltype(detail::downcast_target_impl<T>());
|
||||
```
|
||||
|
||||
`units::downcast` is used to obtain the target type of the downcasting operation registered
|
||||
for a given instantiation in a base type. `detail::downcast_target_impl` checks if a downcasting
|
||||
target is registered for the specific base class. If yes, it returns the registered type,
|
||||
otherwise it works like a regular identity type returning a provided base class.
|
||||
|
||||
```cpp
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
concept has_downcast = requires {
|
||||
downcast_guide(std::declval<downcast_base<T>>());
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
constexpr auto downcast_target_impl()
|
||||
{
|
||||
if constexpr(has_downcast<T>)
|
||||
return decltype(downcast_guide(std::declval<downcast_base<T>>()))();
|
||||
else
|
||||
return T();
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Additionally there is one more simple helper alias provided that is used in the internal
|
||||
library implementation:
|
||||
|
||||
```cpp
|
||||
template<Downcastable T>
|
||||
using downcast_base_t = T::downcast_base_type;
|
||||
```
|
||||
|
||||
|
||||
### `unknown_dimension<Exponent...>`
|
||||
|
||||
Sometimes dimensional calculation results with a class template instantiation that was not
|
||||
predefined by the user in the downcasting facility. A typical example of such a case are
|
||||
temporary results of calculations:
|
||||
|
||||
```cpp
|
||||
units::Length auto d1 = 123q_m;
|
||||
units::Time auto t1 = 10q_s;
|
||||
units::Velocity auto v1 = avg_speed(d1, t1);
|
||||
|
||||
auto temp1 = v1 * 50q_m; // intermediate unknown dimension
|
||||
|
||||
units::Velocity auto v2 = temp1 / 100q_m; // back to known dimensions again
|
||||
units::Length auto d2 = v2 * 60q_s;
|
||||
```
|
||||
|
||||
To provide support to form an unknown derived dimension that could be than be converted to a
|
||||
known one with a correct unit, and also to improve the user experience and clearly state that
|
||||
it is an unknown dimension the library framework will provide an instance of:
|
||||
|
||||
```cpp
|
||||
struct unknown_coherent_unit : unit<unknown_coherent_unit> {};
|
||||
|
||||
template<Exponent E, Exponent... ERest>
|
||||
struct unknown_dimension : derived_dimension<unknown_dimension<E, ERest...>,
|
||||
scaled_unit<ratio<1>, unknown_coherent_unit>,
|
||||
E, ERest...> {
|
||||
using coherent_unit = scaled_unit<ratio<1>, unknown_coherent_unit>;
|
||||
};
|
||||
```
|
||||
|
||||
with this the error log or a debugger breakpoint involving a `temp1` type will include:
|
||||
|
||||
```text
|
||||
units::quantity<units::unknown_dimension<units::exp<units::si::dim_length, 2, 1>,
|
||||
units::exp<units::si::dim_time, -1, 1> >, units::unknown_coherent_unit, long int>
|
||||
```
|
||||
|
||||
|
||||
## Extensibility
|
||||
|
||||
The library was designed with a simple extensibility in mind. It is easy to add new units,
|
||||
dimensions, and prefixes. The systems of units are not closed (classes) but open (namespaces)
|
||||
and can be easily extended, or its content can be partially/fully imported to other systems.
|
||||
|
||||
|
||||
### Adding a new system with custom dimensions and units
|
||||
|
||||
A great example of a adding a whole new system can be a `data` system in the library which
|
||||
adds support for digital information quantities. In summary it adds:
|
||||
1. New prefix type and its prefixes:
|
||||
|
||||
```cpp
|
||||
namespace units::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>> {};
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
2. New units for `information`:
|
||||
|
||||
```cpp
|
||||
namespace units::data {
|
||||
|
||||
struct bit : named_unit<bit, "b", prefix> {};
|
||||
struct kibibit : prefixed_unit<kibibit, kibi, bit> {};
|
||||
|
||||
struct byte : named_scaled_unit<byte, "B", prefix, ratio<8>, bit> {};
|
||||
struct kibibyte : prefixed_unit<kibibyte, kibi, byte> {};
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
3. New base dimension, its concept, and quantity alias:
|
||||
|
||||
```cpp
|
||||
namespace units::data {
|
||||
|
||||
struct dim_information : base_dimension<"information", bit> {};
|
||||
|
||||
template<typename T>
|
||||
concept Information = QuantityOf<T, dim_information>;
|
||||
|
||||
template<Unit U, Scalar Rep = double>
|
||||
using information = quantity<dim_information, U, Rep>;
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
4. UDLs for new units
|
||||
|
||||
```cpp
|
||||
namespace units::data::inline literals {
|
||||
|
||||
// bits
|
||||
constexpr auto operator"" q_b(unsigned long long l) { return information<bit, std::int64_t>(l); }
|
||||
constexpr auto operator"" q_Kib(unsigned long long l) { return information<kibibit, std::int64_t>(l); }
|
||||
|
||||
// bytes
|
||||
constexpr auto operator"" q_B(unsigned long long l) { return information<byte, std::int64_t>(l); }
|
||||
constexpr auto operator"" q_KiB(unsigned long long l) { return information<kibibyte, std::int64_t>(l); }
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
5. A new `bitrate` derived dimension, its units, concept, quantity helper, and UDLs
|
||||
|
||||
```cpp
|
||||
namespace units::data {
|
||||
|
||||
struct bit_per_second : unit<bit_per_second> {};
|
||||
struct dim_bitrate : derived_dimension<dim_bitrate, bit_per_second, exp<dim_information, 1>, exp<si::dim_time, -1>> {};
|
||||
|
||||
struct kibibit_per_second : deduced_unit<kibibit_per_second, dim_bitrate, kibibit, si::second> {};
|
||||
|
||||
template<typename T>
|
||||
concept Bitrate = QuantityOf<T, dim_bitrate>;
|
||||
|
||||
template<Unit U, Scalar Rep = double>
|
||||
using bitrate = quantity<dim_bitrate, U, Rep>;
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
// bits
|
||||
constexpr auto operator"" q_bps(unsigned long long l) { return bitrate<bit_per_second, std::int64_t>(l); }
|
||||
constexpr auto operator"" q_Kibps(unsigned long long l) { return bitrate<kibibit_per_second, std::int64_t>(l); }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Using custom representations
|
||||
|
||||
In theory `quantity` can take any arithmetic-like type as a `Rep` template parameter. In
|
||||
practice some interface is forced by numeric concepts.
|
||||
|
||||
To provide basic library functionality the type should satisfy the `Scalar` concept:
|
||||
|
||||
```cpp
|
||||
template<typename T, typename U = T>
|
||||
concept basic-arithmetic = // exposition only
|
||||
std::magma<std::ranges::plus, T, U> &&
|
||||
std::magma<std::ranges::minus, T, U> &&
|
||||
std::magma<std::ranges::times, T, U> &&
|
||||
std::magma<std::ranges::divided_by, T, U>;
|
||||
|
||||
template<typename T>
|
||||
concept Scalar =
|
||||
(!Quantity<T>) &&
|
||||
(!WrappedQuantity<T>) &&
|
||||
std::regular<T> &&
|
||||
std::totally_ordered<T> &&
|
||||
basic-arithmetic<T>;
|
||||
```
|
||||
|
||||
Where `WrappedQuantity` is a concept that applies `Quantity<typename T::value_type>` recursively
|
||||
on all nested types to check if `T` is not actually a wrapped quantity type (i.e. a vector or
|
||||
matrix of quantities).
|
||||
|
||||
The above implies that the `Rep` type should provide at least:
|
||||
- default constructor, destructor, copy-constructor, and copy-assignment operator
|
||||
- `operator==(Rep, Rep)`, `operator!=(Rep, Rep)`
|
||||
- `operator<(Rep, Rep)`, `operator>(Rep, Rep)`, `operator<=(Rep, Rep)`, `operator>=(Rep, Rep)`
|
||||
- `operator-(Rep)`
|
||||
- `operator+(Rep, Rep)`, `operator-(Rep, Rep)`, `operator*(Rep, Rep)`, `operator*(Rep, Rep)`
|
||||
|
||||
Above also requires that the `Rep` should be implicitly convertible from integral types
|
||||
(i.e. `int`) so a proper implicit converting constructor should be provided.
|
||||
|
||||
Moreover, in most cases to observe expected behavior `Rep` will have to be registered as a
|
||||
floating-point representation type by specializing `units::treat_as_floating_point` type
|
||||
trait:
|
||||
|
||||
```cpp
|
||||
template<typename Rep>
|
||||
inline constexpr bool treat_as_floating_point;
|
||||
```
|
||||
|
||||
An example of such a type can be found in [measurement example](../example/measurement.cpp).
|
||||
|
||||
However, as written above this will enable only a basic functionality of the library. In case
|
||||
additional `quantity` operations are needed the user may opt-in to any of them by providing
|
||||
the equivalent operation for `Rep` type. Here is an additional list of opt-in operations:
|
||||
- `operator++()`
|
||||
- `operator++(int)`
|
||||
- `operator--()`
|
||||
- `operator--(int)`
|
||||
- `operator+=(Rep)`
|
||||
- `operator-=(Rep)`
|
||||
- `operator*=(Rep)`
|
||||
- `operator/=(Rep)`
|
||||
- `operator%=(Rep)`
|
||||
- `operator%(Rep, Rep)`
|
||||
|
||||
`quantity` also has 4 static functions `zero()`, `one()`, `min()`, and `max()` which can
|
||||
be enabled by providing a specialization of `quantity_values` type trait for `Rep` type:
|
||||
|
||||
```cpp
|
||||
template<Scalar Rep>
|
||||
struct quantity_values;
|
||||
```
|
||||
|
||||
## FAQ
|
||||
|
||||
1. 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 we had to 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.
|
||||
|
||||
2. 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.
|
||||
|
||||
3. Why do we spell `metre` instead of `meter`?
|
||||
86
docs/Doxyfile.in
Normal file
86
docs/Doxyfile.in
Normal 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
|
||||
157
docs/INSTALL.md
Normal file
157
docs/INSTALL.md
Normal file
@@ -0,0 +1,157 @@
|
||||
# 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.
|
||||
|
||||
### Conan quick intro
|
||||
|
||||
In case you are not familiar with `conan`, to install it just do:
|
||||
|
||||
```shell
|
||||
pip3 install -U conan
|
||||
```
|
||||
|
||||
After that you might need to add a custom profile in `~/.conan/profile` for your
|
||||
developnment environment. An example profile can look as follows:
|
||||
|
||||
```text
|
||||
[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
|
||||
```
|
||||
|
||||
### Copy
|
||||
|
||||
As `units` is a header-only library you can simply copy `src/include` directory to
|
||||
your source tree and use it as regular header files.
|
||||
|
||||
NOTE: Until C++20 arrives the library has some 3rd party dependencies that provide
|
||||
experimental C++20 features. The list of dependencies include:
|
||||
- `range-v3@ericniebler` (only for gcc-9, gcc-10 uses gcc's concepts implementation)
|
||||
- `fmt@_`
|
||||
|
||||
All of them are easily to obtain with `conan`.
|
||||
|
||||
NOTE: In case a full library's repository is to be compiled (instead of just copying
|
||||
`src/include` headers), additionally, the library's unit tests depend on
|
||||
`Catch2@catchorg` and `linear_algebra@public-conan` conan packages.
|
||||
|
||||
### cmake + conan
|
||||
|
||||
To use `units` as a `cmake` imported library via `cmake` configuration files the following
|
||||
steps may be done:
|
||||
- clone the repository with its submodules:
|
||||
|
||||
```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:
|
||||
|
||||
```shell
|
||||
git submodule update --init
|
||||
```
|
||||
|
||||
- add the following remotes to your local `conan` instance
|
||||
|
||||
```shell
|
||||
conan remote add conan-mpusz https://api.bintray.com/conan/mpusz/conan-mpusz
|
||||
```
|
||||
|
||||
- add `units` as a dependency to your `conan` file. For example to use testing version of
|
||||
`0.5.0` of `mp-units` add:
|
||||
- `conanfile.txt`
|
||||
|
||||
```ini
|
||||
[requires]
|
||||
mp-units/0.5.0@mpusz/testing
|
||||
```
|
||||
|
||||
- `conanfile.py`
|
||||
|
||||
```python
|
||||
requires = "mp-units/0.5.0@mpusz/testing"
|
||||
```
|
||||
|
||||
- import `conan` dependencies to top level `CMakeLists.txt` file
|
||||
|
||||
```cmake
|
||||
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
|
||||
conan_basic_setup(TARGETS)
|
||||
```
|
||||
|
||||
- link your `cmake` target with units
|
||||
|
||||
```cmake
|
||||
target_link_libraries(<your_target> PUBLIC|PRIVATE|INTERFACE CONAN_PKG::mp-units)
|
||||
```
|
||||
|
||||
- install `conan` dependencies before configuring cmake
|
||||
|
||||
```shell
|
||||
cd build
|
||||
conan install .. -pr <your_conan_profile> -s compiler.cppstd=20 -b=outdated -u
|
||||
```
|
||||
|
||||
|
||||
## Full build and unit testing
|
||||
|
||||
In case you would like to build all the code in this repository (with unit tests and examples)
|
||||
you should use the `CMakeLists.txt` from the parent directory and run Conan with
|
||||
`CONAN_RUN_TESTS=True`.
|
||||
|
||||
```shell
|
||||
git clone --recurse-submodules https://github.com/mpusz/units.git
|
||||
mkdir units/build && cd units/build
|
||||
conan remote add linear_algebra https://api.bintray.com/conan/twonington/public-conan
|
||||
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 -VV
|
||||
```
|
||||
|
||||
|
||||
## Packaging
|
||||
|
||||
To create a `conan` package and test `cmake` installation and `conan` packaging run:
|
||||
|
||||
```shell
|
||||
conan create . <username>/<channel> -pr <your_conan_profile> -s compiler.cppstd=20 -e CONAN_RUN_TESTS=True -b outdated
|
||||
```
|
||||
|
||||
|
||||
## Upload package to conan server
|
||||
|
||||
```shell
|
||||
conan upload -r <remote-name> --all mp-units/0.5.0@<user>/<channel>
|
||||
```
|
||||
115
docs/README.md
Normal file
115
docs/README.md
Normal 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
20
docs/_static/css/custom.css
vendored
Normal 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;
|
||||
}
|
||||
BIN
docs/_static/img/design.png
vendored
Normal file
BIN
docs/_static/img/design.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
32
docs/_themes/sphinx_rtd_theme/__init__.py
vendored
Normal file
32
docs/_themes/sphinx_rtd_theme/__init__.py
vendored
Normal 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}
|
||||
82
docs/_themes/sphinx_rtd_theme/breadcrumbs.html
vendored
Normal file
82
docs/_themes/sphinx_rtd_theme/breadcrumbs.html
vendored
Normal 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> »</li>
|
||||
{% for doc in parents %}
|
||||
<li><a href="{{ doc.link|e }}">{{ doc.title }}</a> »</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>
|
||||
56
docs/_themes/sphinx_rtd_theme/footer.html
vendored
Normal file
56
docs/_themes/sphinx_rtd_theme/footer.html
vendored
Normal 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 %}
|
||||
© <a href="{{ path }}">{% trans %}Copyright{% endtrans %}</a> {{ copyright }}
|
||||
{%- else %}
|
||||
{% set copyright = copyright|e %}
|
||||
© {% 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>
|
||||
|
||||
240
docs/_themes/sphinx_rtd_theme/layout.html
vendored
Normal file
240
docs/_themes/sphinx_rtd_theme/layout.html
vendored
Normal 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 = " — "|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>
|
||||
BIN
docs/_themes/sphinx_rtd_theme/locale/de/LC_MESSAGES/sphinx.mo
vendored
Normal file
BIN
docs/_themes/sphinx_rtd_theme/locale/de/LC_MESSAGES/sphinx.mo
vendored
Normal file
Binary file not shown.
208
docs/_themes/sphinx_rtd_theme/locale/de/LC_MESSAGES/sphinx.po
vendored
Normal file
208
docs/_themes/sphinx_rtd_theme/locale/de/LC_MESSAGES/sphinx.po
vendored
Normal 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 "© <a href=\"%(path)s\">Copyright</a> %(copyright)s."
|
||||
#~ msgstr "© <a href=\\\"%(path)s\\\">Copyright</a> %(copyright)s."
|
||||
|
||||
#~ msgid "© Copyright %(copyright)s."
|
||||
#~ msgstr "© 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>."
|
||||
BIN
docs/_themes/sphinx_rtd_theme/locale/en/LC_MESSAGES/sphinx.mo
vendored
Normal file
BIN
docs/_themes/sphinx_rtd_theme/locale/en/LC_MESSAGES/sphinx.mo
vendored
Normal file
Binary file not shown.
147
docs/_themes/sphinx_rtd_theme/locale/en/LC_MESSAGES/sphinx.po
vendored
Normal file
147
docs/_themes/sphinx_rtd_theme/locale/en/LC_MESSAGES/sphinx.po
vendored
Normal 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 ""
|
||||
|
||||
BIN
docs/_themes/sphinx_rtd_theme/locale/es/LC_MESSAGES/sphinx.mo
vendored
Normal file
BIN
docs/_themes/sphinx_rtd_theme/locale/es/LC_MESSAGES/sphinx.mo
vendored
Normal file
Binary file not shown.
149
docs/_themes/sphinx_rtd_theme/locale/es/LC_MESSAGES/sphinx.po
vendored
Normal file
149
docs/_themes/sphinx_rtd_theme/locale/es/LC_MESSAGES/sphinx.po
vendored
Normal 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"
|
||||
|
||||
BIN
docs/_themes/sphinx_rtd_theme/locale/nl/LC_MESSAGES/sphinx.mo
vendored
Normal file
BIN
docs/_themes/sphinx_rtd_theme/locale/nl/LC_MESSAGES/sphinx.mo
vendored
Normal file
Binary file not shown.
152
docs/_themes/sphinx_rtd_theme/locale/nl/LC_MESSAGES/sphinx.po
vendored
Normal file
152
docs/_themes/sphinx_rtd_theme/locale/nl/LC_MESSAGES/sphinx.po
vendored
Normal 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"
|
||||
|
||||
BIN
docs/_themes/sphinx_rtd_theme/locale/ru/LC_MESSAGES/sphinx.mo
vendored
Normal file
BIN
docs/_themes/sphinx_rtd_theme/locale/ru/LC_MESSAGES/sphinx.mo
vendored
Normal file
Binary file not shown.
148
docs/_themes/sphinx_rtd_theme/locale/ru/LC_MESSAGES/sphinx.po
vendored
Normal file
148
docs/_themes/sphinx_rtd_theme/locale/ru/LC_MESSAGES/sphinx.po
vendored
Normal 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 ""
|
||||
|
||||
146
docs/_themes/sphinx_rtd_theme/locale/sphinx.pot
vendored
Normal file
146
docs/_themes/sphinx_rtd_theme/locale/sphinx.pot
vendored
Normal 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 ""
|
||||
|
||||
54
docs/_themes/sphinx_rtd_theme/search.html
vendored
Normal file
54
docs/_themes/sphinx_rtd_theme/search.html
vendored
Normal 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 %}
|
||||
9
docs/_themes/sphinx_rtd_theme/searchbox.html
vendored
Normal file
9
docs/_themes/sphinx_rtd_theme/searchbox.html
vendored
Normal 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 %}
|
||||
1
docs/_themes/sphinx_rtd_theme/static/css/badge_only.css
vendored
Normal file
1
docs/_themes/sphinx_rtd_theme/static/css/badge_only.css
vendored
Normal 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}}
|
||||
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/Roboto-Slab-Bold.woff
vendored
Normal file
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/Roboto-Slab-Bold.woff
vendored
Normal file
Binary file not shown.
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/Roboto-Slab-Bold.woff2
vendored
Normal file
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/Roboto-Slab-Bold.woff2
vendored
Normal file
Binary file not shown.
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/Roboto-Slab-Regular.woff
vendored
Normal file
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/Roboto-Slab-Regular.woff
vendored
Normal file
Binary file not shown.
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/Roboto-Slab-Regular.woff2
vendored
Normal file
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/Roboto-Slab-Regular.woff2
vendored
Normal file
Binary file not shown.
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/fontawesome-webfont.eot
vendored
Normal file
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/fontawesome-webfont.eot
vendored
Normal file
Binary file not shown.
2671
docs/_themes/sphinx_rtd_theme/static/css/fonts/fontawesome-webfont.svg
vendored
Normal file
2671
docs/_themes/sphinx_rtd_theme/static/css/fonts/fontawesome-webfont.svg
vendored
Normal file
File diff suppressed because it is too large
Load Diff
|
After Width: | Height: | Size: 434 KiB |
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/fontawesome-webfont.ttf
vendored
Normal file
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/fontawesome-webfont.ttf
vendored
Normal file
Binary file not shown.
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/fontawesome-webfont.woff
vendored
Normal file
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/fontawesome-webfont.woff
vendored
Normal file
Binary file not shown.
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/fontawesome-webfont.woff2
vendored
Normal file
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/fontawesome-webfont.woff2
vendored
Normal file
Binary file not shown.
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/lato-bold-italic.woff
vendored
Normal file
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/lato-bold-italic.woff
vendored
Normal file
Binary file not shown.
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/lato-bold-italic.woff2
vendored
Normal file
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/lato-bold-italic.woff2
vendored
Normal file
Binary file not shown.
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/lato-bold.woff
vendored
Normal file
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/lato-bold.woff
vendored
Normal file
Binary file not shown.
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/lato-bold.woff2
vendored
Normal file
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/lato-bold.woff2
vendored
Normal file
Binary file not shown.
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/lato-normal-italic.woff
vendored
Normal file
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/lato-normal-italic.woff
vendored
Normal file
Binary file not shown.
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/lato-normal-italic.woff2
vendored
Normal file
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/lato-normal-italic.woff2
vendored
Normal file
Binary file not shown.
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/lato-normal.woff
vendored
Normal file
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/lato-normal.woff
vendored
Normal file
Binary file not shown.
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/lato-normal.woff2
vendored
Normal file
BIN
docs/_themes/sphinx_rtd_theme/static/css/fonts/lato-normal.woff2
vendored
Normal file
Binary file not shown.
4
docs/_themes/sphinx_rtd_theme/static/css/theme.css
vendored
Normal file
4
docs/_themes/sphinx_rtd_theme/static/css/theme.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
docs/_themes/sphinx_rtd_theme/static/js/badge_only.js
vendored
Normal file
1
docs/_themes/sphinx_rtd_theme/static/js/badge_only.js
vendored
Normal 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){}});
|
||||
1
docs/_themes/sphinx_rtd_theme/static/js/theme.js
vendored
Normal file
1
docs/_themes/sphinx_rtd_theme/static/js/theme.js
vendored
Normal 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){}]);
|
||||
18
docs/_themes/sphinx_rtd_theme/theme.conf
vendored
Normal file
18
docs/_themes/sphinx_rtd_theme/theme.conf
vendored
Normal 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 =
|
||||
34
docs/_themes/sphinx_rtd_theme/versions.html
vendored
Normal file
34
docs/_themes/sphinx_rtd_theme/versions.html
vendored
Normal 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
146
docs/conf.py
Normal 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 theme’s 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
BIN
docs/design.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
13
docs/design.rst
Normal file
13
docs/design.rst
Normal 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
67
docs/design/quantity.rst
Normal 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.
|
||||
BIN
docs/downcast_1.png
Normal file
BIN
docs/downcast_1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
BIN
docs/downcast_2.png
Normal file
BIN
docs/downcast_2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
8
docs/examples.rst
Normal file
8
docs/examples.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
Examples
|
||||
========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
examples/hello_units
|
||||
examples/avg_speed
|
||||
8
docs/examples/avg_speed.rst
Normal file
8
docs/examples/avg_speed.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
avg_speed
|
||||
=========
|
||||
|
||||
.. literalinclude:: ../../example/avg_speed.cpp
|
||||
:caption: avg_speed.cpp
|
||||
:start-at: #include
|
||||
:linenos:
|
||||
:force:
|
||||
7
docs/examples/hello_units.rst
Normal file
7
docs/examples/hello_units.rst
Normal 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
44
docs/faq.rst
Normal 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
18
docs/framework.rst
Normal 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
|
||||
22
docs/framework/basic_concepts.rst
Normal file
22
docs/framework/basic_concepts.rst
Normal 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.
|
||||
16
docs/framework/conversions_and_casting.rst
Normal file
16
docs/framework/conversions_and_casting.rst
Normal 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.
|
||||
178
docs/framework/dimensions.rst
Normal file
178
docs/framework/dimensions.rst
Normal 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
|
||||
159
docs/framework/quantities.rst
Normal file
159
docs/framework/quantities.rst
Normal 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.
|
||||
45
docs/framework/text_output.rst
Normal file
45
docs/framework/text_output.rst
Normal 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
319
docs/framework/units.rst
Normal 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), ``m²``
|
||||
(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
4
docs/genindex.rst
Normal file
@@ -0,0 +1,4 @@
|
||||
.. This file is a placeholder and will be replaced during Sphinx build
|
||||
|
||||
Index
|
||||
#####
|
||||
214
docs/glossary.rst
Normal file
214
docs/glossary.rst
Normal 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
49
docs/index.rst
Normal 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
47
docs/introduction.rst
Normal 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
|
||||
46
docs/nomnoml.md
Normal file
46
docs/nomnoml.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# nomnoml
|
||||
|
||||
Graphs in the documentation are created with <http://www.nomnoml.com>.
|
||||
|
||||
## Concepts
|
||||
|
||||
```text
|
||||
[<abstract>Dimension|
|
||||
[base_dimension<Symbol, Unit>]<-[exp<Dimension, Num, Den>]
|
||||
[derived_dimension<Child, Unit, Exponent...>]<-[exp<Dimension, Num, Den>]
|
||||
[exp<Dimension, Num, Den>]<-[derived_dimension<Child, Unit, Exponent...>]
|
||||
]
|
||||
|
||||
[<abstract>Quantity|
|
||||
[quantity<Dimension, Unit, Rep>]
|
||||
]
|
||||
|
||||
[<abstract>Unit]<-[Dimension]
|
||||
[Dimension]<-[Quantity]
|
||||
[Unit]<-[Quantity]
|
||||
```
|
||||
|
||||
## Units
|
||||
|
||||
```text
|
||||
#direction: right
|
||||
|
||||
[scaled_unit<Ratio, Unit>]<:-[unit<Child>]
|
||||
[scaled_unit<Ratio, Unit>]<:-[named_unit<Child, Symbol, PrefixType>]
|
||||
[scaled_unit<Ratio, Unit>]<:-[named_scaled_unit<Child, Symbol, PrefixType, Ratio, Unit>]
|
||||
[scaled_unit<Ratio, Unit>]<:-[prefixed_unit<Child, Prefix, Unit>]
|
||||
[scaled_unit<Ratio, Unit>]<:-[deduced_unit<Child, Dimension, Unit, Unit...>]
|
||||
```
|
||||
|
||||
## Downcasting 1
|
||||
|
||||
```text
|
||||
[detail::derived_dimension_base<exp<si::dim_length, 2>>]<:-[dim_area]
|
||||
```
|
||||
|
||||
## Downcasting 2
|
||||
|
||||
```text
|
||||
[downcast_base<detail::derived_dimension_base<exp<si::dim_length, 2>>>]<:-[detail::derived_dimension_base<exp<si::dim_length, 2>>]
|
||||
[detail::derived_dimension_base<exp<si::dim_length, 2>>]<:-[downcast_child<dim_area, detail::derived_dimension_base<exp<si::dim_length, 2>>>]
|
||||
[downcast_child<dim_area, detail::derived_dimension_base<exp<si::dim_length, 2>>>]<:-[dim_area]```
|
||||
62
docs/quick_start.rst
Normal file
62
docs/quick_start.rst
Normal 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.
|
||||
62
docs/reference/concepts.rst
Normal file
62
docs/reference/concepts.rst
Normal 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>`.
|
||||
15
docs/reference/functions.rst
Normal file
15
docs/reference/functions.rst
Normal 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
|
||||
32
docs/reference/systems.rst
Normal file
32
docs/reference/systems.rst
Normal 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
51
docs/reference/types.rst
Normal 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
3
docs/requirements.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
sphinx
|
||||
recommonmark
|
||||
breathe
|
||||
15
docs/scenarios.rst
Normal file
15
docs/scenarios.rst
Normal 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
|
||||
19
docs/scenarios/extensions.rst
Normal file
19
docs/scenarios/extensions.rst
Normal file
@@ -0,0 +1,19 @@
|
||||
.. namespace:: units
|
||||
|
||||
Extending the library
|
||||
=====================
|
||||
|
||||
Custom Units
|
||||
------------
|
||||
|
||||
Custom Dimensions
|
||||
-----------------
|
||||
|
||||
Custom Base Dimensions
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Custom Derived Dimensions
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Custom Systems
|
||||
--------------
|
||||
41
docs/scenarios/legacy_interfaces.rst
Normal file
41
docs/scenarios/legacy_interfaces.rst
Normal 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.
|
||||
9
docs/scenarios/unknown_units_and_dimensions.rst
Normal file
9
docs/scenarios/unknown_units_and_dimensions.rst
Normal 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
|
||||
BIN
docs/units.png
Normal file
BIN
docs/units.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
233
docs/usage.rst
Normal file
233
docs/usage.rst
Normal 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>
|
||||
Reference in New Issue
Block a user