forked from mpusz/mp-units
docs: initial V2 documenatation added
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
# Code Example
|
||||
|
||||
Here is a small example of operations possible on scalar quantities:
|
||||
|
||||
```cpp
|
||||
#include <mp-units/systems/si/si.h>
|
||||
|
||||
using namespace mp_units::si::unit_symbols;
|
||||
|
||||
// simple numeric operations
|
||||
static_assert(10 * km / 2 == 5 * km);
|
||||
|
||||
// unit conversions
|
||||
static_assert(1 * h == 3600 * s);
|
||||
static_assert(1 * km + 1 * m == 1001 * m);
|
||||
|
||||
// dimension conversions
|
||||
inline constexpr auto kmph = km / h;
|
||||
static_assert(1 * km / (1 * s) == 1000 * (m / s));
|
||||
static_assert(2 * kmph * (2 * h) == 4 * km);
|
||||
static_assert(2 * km / (2 * kmph) == 1 * h);
|
||||
|
||||
static_assert(2 * m * (3 * m) == 6 * m2);
|
||||
|
||||
static_assert(10 * km / (5 * km) == 2);
|
||||
|
||||
static_assert(1000 / (1 * s) == 1 * kHz);
|
||||
```
|
||||
|
||||
!!! example "[Try it on Compiler Explorer](https://godbolt.org/z/j8afKnarv)"
|
||||
|
||||
|
||||
This library requires some C++20 features ([concepts and constraints](https://en.cppreference.com/w/cpp/language/constraints),
|
||||
[classes as NTTP](https://en.cppreference.com/w/cpp/language/template_parameters), ...). Thanks to them,
|
||||
the user gets a powerful but still easy-to-use interface where all unit conversions and dimensional analysis can be
|
||||
performed without sacrificing accuracy. Please see the below example for a quick preview of basic library features:
|
||||
|
||||
*[NTTP]: Non-Type Template Parameter
|
||||
|
||||
```cpp
|
||||
#include <mp-units/format.h>
|
||||
#include <mp-units/iostream.h>
|
||||
#include <mp-units/systems/international/international.h>
|
||||
#include <mp-units/systems/isq/space_and_time.h>
|
||||
#include <mp-units/systems/si/si.h>
|
||||
#include <iostream>
|
||||
|
||||
using namespace mp_units;
|
||||
|
||||
constexpr QuantityOf<isq::speed> auto avg_speed(QuantityOf<isq::length> auto d,
|
||||
QuantityOf<isq::time> auto t)
|
||||
{
|
||||
return d / t;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace mp_units::si::unit_symbols;
|
||||
using namespace mp_units::international::unit_symbols;
|
||||
|
||||
constexpr auto v1 = 110 * (km / h);
|
||||
constexpr auto v2 = 70 * mph;
|
||||
constexpr auto v3 = avg_speed(220. * isq::distance[km], 2 * h);
|
||||
constexpr auto v4 = avg_speed(isq::distance(140. * mi), 2 * h);
|
||||
constexpr auto v5 = v3[m / s];
|
||||
constexpr auto v6 = value_cast<m / s>(v4);
|
||||
constexpr auto v7 = value_cast<int>(v6);
|
||||
|
||||
std::cout << v1 << '\n'; // 110 km/h
|
||||
std::cout << v2 << '\n'; // 70 mi/h
|
||||
std::cout << std::format("{}", v3) << '\n'; // 110 km/h
|
||||
std::cout << std::format("{:*^14}", v4) << '\n'; // ***70 mi/h****
|
||||
std::cout << std::format("{:%Q in %q}", v5) << '\n'; // 30.5556 in m/s
|
||||
std::cout << std::format("{0:%Q} in {0:%q}", v6) << '\n'; // 31.2928 in m/s
|
||||
std::cout << std::format("{:%Q}", v7) << '\n'; // 31
|
||||
}
|
||||
```
|
||||
|
||||
!!! example "[Try it on Compiler Explorer](https://godbolt.org/z/T8bovrqTP)"
|
||||
|
||||
!!! note
|
||||
|
||||
You can find more code examples in the Examples chapter.
|
||||
@@ -0,0 +1,176 @@
|
||||
# Frequently Asked Questions
|
||||
|
||||
## Why do we spell `metre` instead of `meter`?
|
||||
|
||||
This is how ISO 80000 defines it (British English spelling by default).
|
||||
|
||||
|
||||
## Why don't we use UDLs to create quantities?
|
||||
|
||||
Many reasons make UDLs a poor choice for a physical units library:
|
||||
|
||||
1. UDLs work only with literals (compile-time known values). Our observation is that besides
|
||||
the unit tests, there are few compile-time known constants used in the production code.
|
||||
2. Typical implementations of UDLs tend to always use the widest representation type available.
|
||||
In the case of `std::chrono::duration`, the following is true:
|
||||
|
||||
```cpp
|
||||
using namespace std::chrono_literals;
|
||||
auto d1 = 42s;
|
||||
auto d2 = 42.s;
|
||||
static_assert(std::is_same_v<decltype(d1)::rep, std::int64_t>);
|
||||
static_assert(std::is_same_v<decltype(d2)::rep, long double>);
|
||||
```
|
||||
|
||||
3. While increasing the coverage for the library, we learned that many unit symbols conflict with
|
||||
built-in types or numeric extensions. A few of those are: `F` (farad), `J` (joule), `W` (watt),
|
||||
`K` (kelvin), `d` (day), `l` or `L` (litre), `erg`, `ergps`. For a while for those we used `_` prefix
|
||||
to make the library work at all, but at some point, we had to unify the naming, and we came up with `_q_`
|
||||
prefix, which resulted in creating a quantity of a provided unit. So in case the library is
|
||||
standardized, all quantities would be created with UDLs having `q_` prefix (i.e. `42q_s`)
|
||||
which is not that nice anymore.
|
||||
|
||||
4. UDLs with the same identifiers defined in different namespace can't be disambiguated in the C++
|
||||
language. If both SI and CGS systems define `_q_s` UDL for a second unit, then it would not be possible
|
||||
to specify which one to use in case both namespaces are "imported".
|
||||
|
||||
5. Another bad property of UDLs is that they do not compose. A coherent unit of angular momentum would
|
||||
have a UDL specified as `_q_kg_m2_per_s`. Now imagine that you want to make every possible user happy.
|
||||
How many variations of that unit would you predefine for differently scaled versions of unit ingredients?
|
||||
|
||||
6. UDLs are also really expensive to define and specify. For each unit, we need two definitions. One for
|
||||
integral and another one for floating-point representation. Before the V2 framework, the coherent unit of
|
||||
angular momentum was defined as:
|
||||
|
||||
```cpp
|
||||
constexpr auto operator"" _q_kg_m2_per_s(unsigned long long l)
|
||||
{
|
||||
gsl_ExpectsAudit(std::in_range<std::int64_t>(l));
|
||||
return angular_momentum<kilogram_metre_sq_per_second, std::int64_t>(static_cast<std::int64_t>(l));
|
||||
}
|
||||
constexpr auto operator"" _q_kg_m2_per_s(long double l)
|
||||
{
|
||||
return angular_momentum<kilogram_metre_sq_per_second, long double>(l);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Why `60 * km / h` does not compile?
|
||||
|
||||
The library design does not allow multiplying or dividing a quantity (the result of `60 * km`)
|
||||
by another unit. This significantly limits the number of possible errors and surprises in the
|
||||
quantity equations.
|
||||
|
||||
Consider the following expression:
|
||||
|
||||
```cpp
|
||||
auto q = 60 * km / 2 * h;
|
||||
```
|
||||
|
||||
Looks like `30 km/h`, right? But it is not. If the above code was allowed, it would result
|
||||
in `30 km⋅h`. In case you want to divide `60 * km` by `2 * h` a parenthesis is needed
|
||||
`60 * km / (2 * h)`.
|
||||
|
||||
Another surprising issue could result from the following code:
|
||||
|
||||
```cpp
|
||||
template<typename T>
|
||||
auto make_length(T v) { return v * si::metre; }
|
||||
|
||||
auto v = 42;
|
||||
auto q = make_length(v);
|
||||
```
|
||||
|
||||
The above might look like a good idea, but consider what would happen in the user provided
|
||||
an already existing quantity:
|
||||
|
||||
```cpp
|
||||
auto v = 42 * m;
|
||||
auto q = make_length(v);
|
||||
```
|
||||
|
||||
Fortunately, with the current design, such issues are detected at compile-time.
|
||||
|
||||
|
||||
## Why a dimensionless quantity is not just a fundamental arithmetic type?
|
||||
|
||||
In the initial design of this library, the resulting type of division of two quantities was their
|
||||
common representation type:
|
||||
|
||||
```cpp
|
||||
static_assert(std::is_same_v<decltype(10 * km / (5 * km)), std::int64_t>);
|
||||
```
|
||||
|
||||
First of all, this was consistent with
|
||||
[`std::chrono::duration`](https://en.cppreference.com/w/cpp/chrono/duration/operator_arith4) behavior.
|
||||
Additional reasoning behind it was not providing a false impression of a strong `quantity` type for
|
||||
something that looks and feels like a regular number. Also, all of the mathematic and trigonometric functions
|
||||
were working fine out of the box with such representation types, so we did not have to rewrite
|
||||
`sin()`, `cos()`, `exp()`, and others.
|
||||
|
||||
However, the feedback we got from the production usage was that such an approach is really bad for generic
|
||||
programming. It is hard to handle the result of the two quantities' division (or multiplication) as
|
||||
it might be either a quantity or a fundamental type. If we want to raise such a result to some power, we
|
||||
must use `units::pow` or `std::pow` depending on the resulting type. Those are only a few issues related
|
||||
to such an approach.
|
||||
|
||||
Moreover, suppose you divide quantities of the same dimension but with units of significantly different
|
||||
magnitudes. In that case, you may end up with a really small or a huge floating-point value, which may result
|
||||
in losing lots of precision. Returning a dimensionless quantity from such cases allows us to benefit from
|
||||
all the properties of scaled units and is consistent with the rest of the library.
|
||||
|
||||
!!! info
|
||||
|
||||
More information on the current design can be found in the Dimensionless Quantities chapter.
|
||||
|
||||
|
||||
## Why Unicode quantity symbols are used by default instead of ASCII-only characters?
|
||||
|
||||
Both C++ and ISO 80000 are standardized by the ISO. ISO 80000 and the SI standards specify Unicode symbols
|
||||
as the official unit names for some quantities (i.e. `Ω` symbol for the resistance quantity).
|
||||
As **mp-units** library will be proposed for standardization as a part of the C++ Standard Library
|
||||
we have to obey the rules and be consistent with ISO specifications.
|
||||
|
||||
!!! info
|
||||
|
||||
We do understand engineering reality and the constraints of some environments. This is why the library
|
||||
has the option of ASCII-only Quantity Symbols.
|
||||
|
||||
|
||||
## Why don't you have CMake options to disable the building of tests and examples?
|
||||
|
||||
Over time many people provided PRs proposing adding options to build tests and examples conditionally.
|
||||
Here are a few examples:
|
||||
|
||||
- [Add CMake options for disabling docs, examples and tests](https://github.com/mpusz/mp-units/pull/124)
|
||||
- [build: add options to disable part of the build](https://github.com/mpusz/mp-units/pull/402)
|
||||
- [CMake Refactoring and Option Cleanup](https://github.com/mpusz/mp-units/pull/456)
|
||||
|
||||
We admit this is a common practice in the industry, but we also believe this is a bad pattern.
|
||||
|
||||
First, the only need for such options comes when a user wants to use `add_subdirectory()` in CMake
|
||||
to handle dependencies. Such an approach does not scale and should be discouraged. There is little
|
||||
use for such a practice in times when we have dedicated package managers like Conan.
|
||||
|
||||
The second thing is that our observation is that many people are fixed on disabling "unneeded" subdirectories
|
||||
from compilation, but they do not see or address the biggest issue, which is polluting user's build
|
||||
environment with our development-specific settings. Propagating our restrictive compilation flags to user's
|
||||
project is not the best idea as it might cause a lot of harm if this project stops to compile
|
||||
because of that.
|
||||
|
||||
Last but not least, not having those options is on purpose. Top level _CMakeLists.txt_ file should only
|
||||
be used by **mp-units** developers and contributors as an entry point for project's development.
|
||||
We want to ensure that everyone will build **ALL** the code correctly before pushing a commit. Having
|
||||
such options would allow unintended issues to leak to PRs and CI.
|
||||
|
||||
This is why our projects have two entry points:
|
||||
|
||||
- _./CMakeLists.txt_ is to be used by projects developers to build **ALL** the project code with really
|
||||
restrictive compilation flags,
|
||||
- _./src/CMakeLists.txt_ contains only a pure library definition and should be used by the customers
|
||||
that prefer to use CMake's `add_subdirectory()` to handle the dependencies.
|
||||
|
||||
!!! info
|
||||
|
||||
For more details on this please refer to the [CMake + Conan: 3 Years Later - Mateusz Pusz](https://youtu.be/mrSwJBJ-0z8?t=1931)
|
||||
lecture that Mateusz Pusz provided at the C++Now 2021 conference.
|
||||
@@ -0,0 +1,449 @@
|
||||
# Installation And Usage
|
||||
|
||||
!!! info
|
||||
|
||||
**mp-units** library tries to provide the best user experience possible with the C++ language.
|
||||
To achieve that, it extensively uses C++20 features and the
|
||||
[explicit object parameter](https://en.cppreference.com/w/cpp/language/member_functions#Explicit_object_parameter)
|
||||
from C++23.
|
||||
|
||||
Even though the library benefits from C++23 (if available), C++20 is enough to compile and
|
||||
use all of the library's functionality. C++23 features are hidden behind a preprocessor macro
|
||||
providing a backward-compatible way to use it.
|
||||
|
||||
Sadly, as of today, not many compilers provide full C++20 support. The library compiles fine
|
||||
on the following compilers (or newer):
|
||||
|
||||
- gcc-12.2
|
||||
|
||||
In the upcoming weeks, we will be actively working to extend the support to other compilers as well.
|
||||
|
||||
|
||||
## Repository Structure and Dependencies
|
||||
|
||||
This repository contains three independent CMake-based projects:
|
||||
|
||||
- _./src_
|
||||
|
||||
- header-only project containing whole **mp-units** library
|
||||
- _./src/CMakeList.txt_ file is intended as an **entry point for library users**
|
||||
- in case this library becomes part of the C++ standard, it will have no external dependencies
|
||||
but until then, it depends on the following:
|
||||
|
||||
- [gsl-lite](https://github.com/gsl-lite/gsl-lite) to verify runtime contracts with
|
||||
the `gsl_Expects` macro,
|
||||
- [{fmt}](https://github.com/fmtlib/fmt) to provide text formatting of quantities
|
||||
(if `std::format` is not supported yet on a specific compiler),
|
||||
- [only for clang < 14 with libc++] [range-v3](https://github.com/ericniebler/range-v3)
|
||||
to provide needed C++20 concepts and utilities.
|
||||
|
||||
- _._
|
||||
|
||||
- project used as an **entry point for library development and CI/CD**
|
||||
- it wraps _./src_ project together with usage examples and tests
|
||||
- additionally to the dependencies of _./src_ project, it uses:
|
||||
|
||||
- `Catch2 <https://github.com/catchorg/Catch2>`_ library as a unit tests framework,
|
||||
- `linear algebra <https://github.com/BobSteagall/wg21/tree/master/include>`_
|
||||
library based on proposal `P1385 <https://wg21.link/P1385>`_ used in some examples
|
||||
and tests.
|
||||
|
||||
- in case you also want to generate the project's documentation, you will need:
|
||||
|
||||
- [Material for MkDocs](https://squidfunk.github.io/mkdocs-material)
|
||||
|
||||
- *./test_package*
|
||||
|
||||
- library installation and Conan package verification.
|
||||
|
||||
|
||||
!!! tip
|
||||
|
||||
Top level _CMakeLists.txt_ file should only be used by **mp-units** developers and contributors
|
||||
as an entry point for the project's development. We want to ensure that everyone will build **ALL**
|
||||
the code correctly before pushing a commit. Having such options would allow unintended issues to
|
||||
leak to PRs and CI.
|
||||
|
||||
This is why our projects have two entry points:
|
||||
|
||||
- _./CMakeLists.txt_ is to be used by projects developers to build **ALL** the project code with really
|
||||
restrictive compilation flags,
|
||||
- _./src/CMakeLists.txt_ contains only a pure library definition and should be used by the customers
|
||||
that prefer to use CMake's `add_subdirectory()` to handle the dependencies.
|
||||
|
||||
To learn more about the rationale, please check our [FAQ](../faq/#why-dont-you-have-cmake-options-to-disable-building-of-tests-and-examples).
|
||||
|
||||
|
||||
## Obtaining Dependencies
|
||||
|
||||
This library assumes that most of the dependencies will be provided by the
|
||||
[Conan Package Manager](https://conan.io/). If you want to obtain required
|
||||
dependencies by other means, some modifications to the library's CMake files might be needed.
|
||||
The rest of the dependencies responsible for documentation generation are provided by
|
||||
`python3-pip`.
|
||||
|
||||
|
||||
### Conan Quick Intro
|
||||
|
||||
In case you are not familiar with Conan, to install it (or upgrade) just do:
|
||||
|
||||
```shell
|
||||
pip3 install -U conan
|
||||
```
|
||||
|
||||
After that, you might need to add a custom profile file for your development environment
|
||||
in _~/.conan2/profiles_ directory. An example profile can look as follows:
|
||||
|
||||
```ini hl_lines="5" title="~/.conan2/profiles/gcc12"
|
||||
[settings]
|
||||
arch=x86_64
|
||||
build_type=Release
|
||||
compiler=gcc
|
||||
compiler.cppstd=20
|
||||
compiler.libcxx=libstdc++11
|
||||
compiler.version=12
|
||||
os=Linux
|
||||
|
||||
[conf]
|
||||
tools.build:compiler_executables={"c": "gcc-12", "cpp": "g++-12"}
|
||||
```
|
||||
|
||||
!!! tip
|
||||
|
||||
Please note that the **mp-units** library requires C++20 to be set in a Conan profile or forced
|
||||
via the Conan command line. If you do the former, you will not need to provide `-s compiler.cppstd=20`
|
||||
every time your run a Conan command line (as provided in the command line instructions below).
|
||||
|
||||
Additionally, it is recommended to set Ninja as a CMake generator for Conan. To do so, you should create
|
||||
a _~/.conan2/global.conf_ file that will set `tools.cmake.cmaketoolchain:generator` to one of Ninja
|
||||
generators. For example:
|
||||
|
||||
```text title="~/.conan2/global.conf"
|
||||
tools.cmake.cmaketoolchain:generator="Ninja Multi-Config"
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
_~/.conan2/global.conf_ file may also set `tools.cmake.cmake_layout:build_folder_vars` which
|
||||
[makes working with several compilers or build configurations easier](https://docs.conan.io/2/reference/tools/cmake/cmake_layout.html#multi-setting-option-cmake-layout).
|
||||
For example, the below line will force Conan to generate separate CMake presets and folders for
|
||||
each compiler:
|
||||
|
||||
```text title="~/.conan2/global.conf"
|
||||
tools.cmake.cmake_layout:build_folder_vars=["settings.compiler", "settings.compiler.version"]
|
||||
```
|
||||
|
||||
In such a case, you will need to use a configuration-specific preset name in the Conan instructions
|
||||
provided below rather then just `conan-default` and `conan-release`
|
||||
(i.e. `conan-gcc-11` and `conan-gcc-11-release`)
|
||||
|
||||
|
||||
## Build Options
|
||||
|
||||
### Conan Configuration Properties
|
||||
|
||||
[`user.build:all`](#user-build-all){ #user-build-all }
|
||||
|
||||
: [:octicons-tag-24: 0.8.0][build all support] · :octicons-milestone-24: `True`/`False` (Default: `False`)
|
||||
|
||||
Enables compilation of all the source code including tests and examples. To support
|
||||
this it requires some additional Conan build dependencies described in
|
||||
[Repository Structure and Dependencies](#repository-structure-and-dependencies).
|
||||
It also runs unit tests during Conan build (unless `tools.build:skip_test`
|
||||
configuration property is set to `True`).
|
||||
|
||||
[build all support]: https://github.com/mpusz/mp-units/releases/tag/v0.8.0
|
||||
|
||||
|
||||
[`user.build:skip_la`](#user-skip-la){ #user-skip-la }
|
||||
|
||||
: [:octicons-tag-24: 0.8.0][skip la support] · :octicons-milestone-24: `True`/`False` (Default: `False`)
|
||||
|
||||
If `user.build:all` is enabled, among others, Conan installs the external
|
||||
[wg21-linear_algebra](https://conan.io/center/wg21-linear_algebra)
|
||||
dependency and enables the compilation of linear algebra-based tests and usage examples.
|
||||
Such behavior can be disabled with this option.
|
||||
|
||||
[skip la support]: https://github.com/mpusz/mp-units/releases/tag/v0.8.0
|
||||
|
||||
|
||||
### CMake Options
|
||||
|
||||
[`MP_UNITS_AS_SYSTEM_HEADERS`](#MP_UNITS_AS_SYSTEM_HEADERS){ #MP_UNITS_AS_SYSTEM_HEADERS }
|
||||
|
||||
: [:octicons-tag-24: 2.0.0][as system headers support] · :octicons-milestone-24: `ON`/`OFF` (Default: `OFF`)
|
||||
|
||||
Exports library as system headers.
|
||||
|
||||
[as system headers support]: https://github.com/mpusz/mp-units/releases/tag/v2.0.0
|
||||
|
||||
|
||||
[`MP_UNITS_BUILD_LA`](#MP_UNITS_BUILD_LA){ #MP_UNITS_BUILD_LA }
|
||||
|
||||
: [:octicons-tag-24: 2.0.0][build la support] · :octicons-milestone-24: `ON`/`OFF` (Default: `ON`)
|
||||
|
||||
Enables building code depending on the linear algebra library.
|
||||
|
||||
[build la support]: https://github.com/mpusz/mp-units/releases/tag/v2.0.0
|
||||
|
||||
|
||||
[`MP_UNITS_IWYU`](#MP_UNITS_IWYU){ #MP_UNITS_IWYU }
|
||||
|
||||
: [:octicons-tag-24: 2.0.0][iwyu support] · :octicons-milestone-24: `ON`/`OFF` (Default: `OFF`)
|
||||
|
||||
Enables `include-what-you-use` when compiling with a clang compiler.
|
||||
Additionally turns on [`MP_UNITS_AS_SYSTEM_HEADERS`](#MP_UNITS_AS_SYSTEM_HEADERS).
|
||||
|
||||
[iwyu support]: https://github.com/mpusz/mp-units/releases/tag/v2.0.0
|
||||
|
||||
|
||||
[`MP_UNITS_USE_LIBFMT`](#MP_UNITS_USE_LIBFMT){ #MP_UNITS_USE_LIBFMT }
|
||||
|
||||
: [:octicons-tag-24: 2.0.0][use libfmt support] · :octicons-milestone-24: `ON`/`OFF` (Default: `ON`)
|
||||
|
||||
Enables usage of [{fmt}](https://github.com/fmtlib/fmt) library instead of the C++20 Standard
|
||||
Library feature.
|
||||
|
||||
[use libfmt support]: https://github.com/mpusz/mp-units/releases/tag/v2.0.0
|
||||
|
||||
|
||||
## CMake with Presets Support
|
||||
|
||||
It is recommended to use at least CMake 3.23 to build this project as this version introduced support
|
||||
for CMake Presets schema version 4 used now by Conan to generate presets files. All build instructions
|
||||
below assume that you have such support. If not, your CMake invocations have to be replaced with something
|
||||
like:
|
||||
|
||||
```shell
|
||||
mkdir build && cd build
|
||||
cmake .. -G "Ninja Multi-Config" -DCMAKE_TOOLCHAIN_FILE=<path_to_generators_dir>/conan_toolchain.cmake
|
||||
cmake --build . --config Release
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
In case you can't use CMake 3.23 but you have access to CMake 3.20 or later, you can append
|
||||
`-c tools.cmake.cmaketoolchain.presets:max_schema_version=2` to the `conan install` command
|
||||
which will force Conan to use an older version of the CMake Presets schema.
|
||||
|
||||
|
||||
## Installation and Reuse
|
||||
|
||||
There are many different ways of installing/reusing **mp-units** in your project. Below we mention
|
||||
only a few of many options possible.
|
||||
|
||||
!!! info
|
||||
|
||||
The easiest and most recommended way to obtain **mp-units** is with the Conan package manager.
|
||||
See [Conan + CMake (release)](#conan-cmake-release) for a detailed instruction.
|
||||
|
||||
|
||||
### Copy
|
||||
|
||||
As **mp-units** is a C++ header-only library you can simply copy all needed _src/*/include_ subdirectories
|
||||
to your source tree.
|
||||
|
||||
!!! note
|
||||
|
||||
In such a case, you are on your own to ensure all the dependencies are installed, and their header
|
||||
files can be located during the build. Please also note that some compiler-specific flags are needed
|
||||
to make the code compile without issues.
|
||||
|
||||
|
||||
### Copy + CMake
|
||||
|
||||
If you copy the whole **mp-units** repository to your project's file tree, you can reuse CMake targets
|
||||
defined by the library. To do so, you should use _CMakeLists.txt_ file from the _./src_ directory:
|
||||
|
||||
```cmake
|
||||
add_subdirectory(<path_to_units_folder>/src)
|
||||
# ...
|
||||
target_link_libraries(<your_target> <PUBLIC|PRIVATE|INTERFACE> mp-units::mp-units)
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
You are still on your own to make sure all the dependencies are installed and their header and CMake
|
||||
configuration files can be located during the build.
|
||||
|
||||
|
||||
### Conan + CMake (release)
|
||||
|
||||
!!! tip
|
||||
|
||||
If you are new to the Conan package manager, it is highly recommended to read
|
||||
[Obtaining Dependencies](#obtaining-dependencies) and refer to
|
||||
[Consuming packages](https://docs.conan.io/2/tutorial/consuming_packages.html)
|
||||
chapter of the official Conan documentation for more information.
|
||||
|
||||
**mp-units** releases are hosted on [Conan-Center](https://conan.io/center/mp-units).
|
||||
To obtain an official library release, the following steps may be performed:
|
||||
|
||||
1. Create Conan configuration file (either _conanfile.txt_ or _conanfile.py_) in your
|
||||
project's top-level directory and add **mp-units** as a dependency of your project.
|
||||
For example, the simplest file may look as follows:
|
||||
|
||||
```ini title="conanfile.txt"
|
||||
[requires]
|
||||
mp-units/0.8.0
|
||||
|
||||
[layout]
|
||||
cmake_layout
|
||||
|
||||
[generators]
|
||||
CMakeToolchain
|
||||
CMakeDeps
|
||||
```
|
||||
|
||||
2. Import **mp-units** and its dependencies definitions to your project's build procedure
|
||||
with `find_package`:
|
||||
|
||||
```cmake
|
||||
find_package(mp-units CONFIG REQUIRED)
|
||||
```
|
||||
|
||||
3. Link your CMake targets with **mp-units**:
|
||||
|
||||
```cmake
|
||||
target_link_libraries(<your_target> <PUBLIC|PRIVATE|INTERFACE> mp-units::mp-units)
|
||||
```
|
||||
|
||||
4. Download, build, and install Conan dependencies before running the CMake configuration step:
|
||||
|
||||
```shell
|
||||
conan install . -pr <your_conan_profile> -s compiler.cppstd=20 -b=missing
|
||||
cmake --preset conan-default
|
||||
cmake --build --preset conan-release
|
||||
```
|
||||
|
||||
### Conan + CMake (Live At Head)
|
||||
|
||||
This chapter describes the procedure to Live At Head, which means using the latest version
|
||||
of **mp-units** all the time.
|
||||
|
||||
!!! note
|
||||
|
||||
Please note that even though the Conan packages that you will be using are generated **ONLY**
|
||||
for builds that are considered stable (passed our CI tests) some minor regressions may happen
|
||||
(our CI and C++20 build environment is not perfect yet). Also, please expect that the library
|
||||
interface might, and probably will, change occasionally. Even though we do our best, such
|
||||
changes might not be reflected in the project's documentation right away.
|
||||
|
||||
The procedure is similar to the one described in [Conan + CMake (release)](#conan-cmake-release)
|
||||
with the following differences:
|
||||
|
||||
1. Before starting the previous procedure, add **mp-units** remote to your Conan configuration:
|
||||
|
||||
```shell
|
||||
conan remote add conan-mpusz https://mpusz.jfrog.io/artifactory/api/conan/conan-oss
|
||||
```
|
||||
|
||||
2. In your Conan configuration file, provide the package identifier of the `mpusz/testing` stream:
|
||||
|
||||
```ini title="conanfile.txt" hl_lines="2"
|
||||
[requires]
|
||||
mp-units/2.0.0@mpusz/testing
|
||||
|
||||
[layout]
|
||||
cmake_layout
|
||||
|
||||
[generators]
|
||||
CMakeToolchain
|
||||
CMakeDeps
|
||||
```
|
||||
|
||||
!!! tip
|
||||
|
||||
The identifiers of the latest packages can always be found in
|
||||
[the project's README file](https://github.com/mpusz/mp-units/blob/master/README.md) or on
|
||||
[the project's Artifactory](https://mpusz.jfrog.io/ui/packages/conan:%2F%2Fmp-units).
|
||||
|
||||
3. Force Conan to check for updated recipes with `-u`:
|
||||
|
||||
```shell
|
||||
conan install . -pr <your_conan_profile> -s compiler.cppstd=20 -b=missing -u
|
||||
```
|
||||
|
||||
|
||||
### Install
|
||||
|
||||
In case you don't want to use Conan in your project and just want to install the **mp-units**
|
||||
library on your file system and use `find_package(mp-units)` from another repository
|
||||
to find it, it is enough to perform the following steps:
|
||||
|
||||
```shell
|
||||
conan install . -pr <your_conan_profile> -s compiler.cppstd=20 -b=missing
|
||||
mv CMakeUserPresets.json src
|
||||
cd src
|
||||
cmake --preset conan-default -DCMAKE_INSTALL_PREFIX=<your_installation_path>
|
||||
cmake --build --preset conan-release --target install
|
||||
```
|
||||
|
||||
|
||||
## Contributing (or just building all the tests and examples)
|
||||
|
||||
In case you would like to build all the **mp-units** source code (with unit tests and examples),
|
||||
you should:
|
||||
|
||||
1. Use the _CMakeLists.txt_ from the top-level directory.
|
||||
2. Run Conan with [`user.build:all`](#user-build-all) = `True`.
|
||||
|
||||
```shell
|
||||
git clone https://github.com/mpusz/mp-units.git && cd units
|
||||
conan build . -pr <your_conan_profile> -s compiler.cppstd=20 -c user.build:all=True -b missing
|
||||
```
|
||||
|
||||
The above will download and install all of the dependencies needed for the development of the library,
|
||||
build all of the source code, and run unit tests.
|
||||
|
||||
If you prefer to build the project via CMake rather than Conan, then you should replace
|
||||
the `conan build` with `conan install` command and then follow with a regular CMake build:
|
||||
|
||||
```shell
|
||||
cmake --preset conan-default
|
||||
cmake --build --preset conan-release
|
||||
cmake --build --preset conan-release --target test
|
||||
```
|
||||
|
||||
|
||||
## Building documentation
|
||||
|
||||
Starting from **mp-units 2.0** we are using [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/)
|
||||
to build our documentation. The easiest way to install all the required dependencies
|
||||
is with `pip`:
|
||||
|
||||
```shell
|
||||
pip install -U mkdocs-material
|
||||
```
|
||||
|
||||
After that, you can either:
|
||||
|
||||
- easily [start a live server to preview the documentation as you write](https://squidfunk.github.io/mkdocs-material/creating-your-site/#previewing-as-you-write)
|
||||
|
||||
```shell
|
||||
mkdocs serve
|
||||
```
|
||||
|
||||
- [build the documentation](https://squidfunk.github.io/mkdocs-material/creating-your-site/#building-your-site)
|
||||
|
||||
```shell
|
||||
mkdocs build
|
||||
```
|
||||
|
||||
|
||||
## Packaging
|
||||
|
||||
To test CMake installation and Conan packaging or create a Conan package run:
|
||||
|
||||
```shell
|
||||
conan create . <username>/<channel> -pr <your_conan_profile> -s compiler.cppstd=20 -c user.build:all=True -b missing
|
||||
```
|
||||
|
||||
The above will create a Conan package and run tests provided in _./test_package_ directory.
|
||||
|
||||
|
||||
## Uploading **mp-units** Package to the Conan Server
|
||||
|
||||
```shell
|
||||
conan upload -r <remote-name> --all mp-units/2.0.0@<user>/<channel>
|
||||
```
|
||||
@@ -0,0 +1,50 @@
|
||||
# Introduction
|
||||
|
||||
**mp-units** is a Modern C++ library that provides compile-time dimensional analysis and unit/quantity
|
||||
manipulation. The initial versions of the library were inspired by the
|
||||
[`std::chrono::duration`](https://en.cppreference.com/w/cpp/chrono/duration)
|
||||
but with each release, the interfaces diverged from the original to provide a better user
|
||||
experience.
|
||||
|
||||
|
||||
## Open Source
|
||||
|
||||
**mp-units** is Free and Open Source, with a permissive
|
||||
[MIT license](https://github.com/mpusz/mp-units/blob/master/LICENSE.md). Check out the source
|
||||
code and issue tracking (for questions and support, reporting bugs, suggesting feature requests
|
||||
and improvements) at <https://github.com/mpusz/mp-units>.
|
||||
|
||||
|
||||
## With the User's Experience in Mind
|
||||
|
||||
Most of the critical design decisions in the library are dictated by the requirement of
|
||||
providing the best user experience possible. Other C++ physical units libraries are
|
||||
"famous" for their enormous and hard-to-understand error messages (one line of the error log often
|
||||
do not fit on one slide). The ultimate goal of **mp-units** is to improve this and make compile-time
|
||||
errors and debugging as easy and user-friendly as possible.
|
||||
|
||||
To achieve this goal, several techniques are applied:
|
||||
|
||||
- usage of C++20 concepts,
|
||||
- using strong types for framework entities (instead of type aliases),
|
||||
- usage of expression templates to improve the readability of generated types,
|
||||
- limiting the number of template arguments to the bare minimum.
|
||||
|
||||
!!! note
|
||||
|
||||
In many generic C++ libraries compile-time errors do not happen often. It is hard to
|
||||
break `std::string` or `std::vector` in a way it won't compile with a huge error
|
||||
log. Physical Units libraries are different. **Generation of compile-time errors
|
||||
is the main reason to use such a library.**
|
||||
|
||||
|
||||
## Key Features
|
||||
|
||||
| Feature | Description |
|
||||
|------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| **Safety** | - The affine space strong types (`quantity` and `quantity_point`)<br>- Compile-time checked conversions of quantities and units<br>- Unique support for many quantities of the same kind<br>- Type-safe equations on scalar, vector, and tensor quantities and their units<br>- Value-preserving conversions |
|
||||
| **Performance** | - All the compile-time logic implemented as immediate (`consteval`) functions<br>- As fast or even faster than working with fundamental types<br>- No space size overhead needed to implement high-level abstractions |
|
||||
| **Great User Experience** | - Optimized for readable compilation errors and great debugging experience<br>- Efficient and composable way to specify a unit of choice<br>- Value-based dimension, unit, and quantity equations |
|
||||
| **Feature Rich** | - Systems of Quantities<br>- Systems of Units<br>- Scalar, vector, and tensor quantities<br>- The affine space<br>- [Natural units systems](https://en.wikipedia.org/wiki/Natural_units) support<br>- Strong angular system<br>- Supports any unit's magnitude (huge, small, floating-point)<br>- Faster-than-lightspeed constants<br>- Highly adjustable text-output formatting |
|
||||
| **Easy to Extend** | - Each entity can be defined with a single line of code<br>- User can easily extend the systems with custom dimensions, quantities, and units |
|
||||
| **Low Standardization Cost** | - Small number of predefined entities needed thanks to composability<br>- No external dependencies (assuming full C++20 support)<br>- No macros in the user interface (besides portability and standard-compliance issues)<br>- Possibility to be standardized as a [freestanding](https://en.cppreference.com/w/cpp/freestanding) part of the C++ Standard Library |
|
||||
@@ -0,0 +1,76 @@
|
||||
# Quick Start
|
||||
|
||||
A **quantity** is a concrete amount of a unit for a quantity type of a specified dimension with a
|
||||
specific representation, and is represented in the library with a `quantity` class template.
|
||||
|
||||
|
||||
## Creating a quantity
|
||||
|
||||
The quantity is created by multiplying a number with a predefined unit:
|
||||
|
||||
```cpp
|
||||
#include <mp-units/systems/si/si.h>
|
||||
|
||||
using namespace mp_units;
|
||||
|
||||
auto q = 42 * si::metre;
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
The above spelling of `metre` is not a typo. For motivation, please check our
|
||||
[FAQ](../faq/#why-do-we-spell-metre-instead-of-meter).
|
||||
|
||||
The above creates an instance of `quantity<si::metre(), int>`. The same can be obtained using
|
||||
an optional unit symbol:
|
||||
|
||||
```cpp
|
||||
#include <mp-units/systems/si/si.h>
|
||||
|
||||
using namespace mp_units;
|
||||
using namespace mp_units::si::unit_symbols;
|
||||
|
||||
auto q = 42 * m;
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
Unit symbols introduce a lot of short identifiers into the current namespace, and that is
|
||||
why they are opt-in. A user has to explicitly "import" them from a dedicated `unit_symbols`
|
||||
namespace.
|
||||
|
||||
|
||||
## User-provided unit wrappers
|
||||
|
||||
Sometimes it might be awkward to type some derived units:
|
||||
|
||||
```cpp
|
||||
auto speed = 60 * (km / h);
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
Please note that `60 * km / h` will not compile. To read more about the rationale for such
|
||||
a design please check our [FAQ](../faq/#why-dont-we-use-udls-to-create-a-quantity).
|
||||
|
||||
In case such a unit is used a lot in the project, a user can easily provide a nicely named
|
||||
wrapper for it with:
|
||||
|
||||
```cpp
|
||||
constexpr auto kmph = km / h;
|
||||
auto speed = 60 * kmph;
|
||||
```
|
||||
|
||||
or even:
|
||||
|
||||
```cpp
|
||||
constexpr auto kilometre = si::kilo<si::metre>;
|
||||
constexpr auto kilometre_per_hour = kilometre / si::hour;
|
||||
constexpr auto kmph = kilometre_per_hour;
|
||||
auto speed = 60 * kmph;
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
In case you wonder why this library does not use UDLs to create quantities, please check
|
||||
our [FAQ](../faq/#why-dont-we-use-udls-to-create-quantities).
|
||||
Reference in New Issue
Block a user