mirror of
https://github.com/mpusz/mp-units.git
synced 2025-08-01 03:14:29 +02:00
Merge remote-tracking branch 'mpusz/master' into master-msvc-194
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
include: ["cmake/.cmake-format-additional_commands-jegp.cmake_modules.yaml"]
|
||||
parse:
|
||||
additional_commands:
|
||||
add_mp_units_module:
|
||||
|
28
.github/workflows/documentation.yml
vendored
28
.github/workflows/documentation.yml
vendored
@@ -46,14 +46,36 @@ jobs:
|
||||
path: .cache
|
||||
restore-keys: |
|
||||
mkdocs-material-
|
||||
- name: Installing pip packages
|
||||
run: |
|
||||
pip install conan mkdocs-material mkdocs-rss-plugin mkdocs-material[imaging] mike
|
||||
- name: Prepare git
|
||||
run: |
|
||||
git config --global user.name github-actions
|
||||
git config --global user.email github-actions@github.com
|
||||
git fetch origin gh-pages --depth=1
|
||||
- name: Installing API reference dependencies
|
||||
run: |
|
||||
sudo apt install haskell-stack graphviz nodejs npm ghc cabal-install
|
||||
npm install split mathjax-full mathjax-node-sre
|
||||
cabal update
|
||||
- name: Installing MathJax-Node-CLI
|
||||
run: |
|
||||
git clone https://github.com/mathjax/mathjax-node-cli --depth=1
|
||||
echo "${{ github.workspace }}/mathjax-node-cli/bin" >> $GITHUB_PATH
|
||||
- name: Get git repos with API reference tools
|
||||
run: |
|
||||
git clone https://github.com/JohelEGP/jegp.cmake_modules.git --depth=1
|
||||
git clone https://github.com/JohelEGP/draft.git --branch=standardese_sources_base --depth=1
|
||||
git clone https://github.com/JohelEGP/cxxdraft-htmlgen.git --branch=standardese_sources_base --depth=1
|
||||
- name: Generate API reference
|
||||
run: |
|
||||
cmake -S docs/api_reference/src -B build \
|
||||
-DCMAKE_MODULE_PATH="${{ github.workspace }}/jegp.cmake_modules/modules" \
|
||||
-DJEGP_STANDARDESE_SOURCES_GIT_REPOSITORY="${{ github.workspace }}/draft" \
|
||||
-DJEGP_CXXDRAFT_HTMLGEN_GIT_REPOSITORY="${{ github.workspace }}/cxxdraft-htmlgen"
|
||||
cmake --build build
|
||||
mv build/mp-units.html docs/api_reference/gen
|
||||
- name: Installing pip dependencies
|
||||
run: |
|
||||
pip install conan mkdocs-material mkdocs-rss-plugin mkdocs-material[imaging] mkdocs-exclude mike
|
||||
- name: Building docs
|
||||
run: |
|
||||
mike deploy --push --update-aliases `conan inspect . | sed -n -r 's/version: ([0-9]+.[0-9]+).[0-9]+/\1/p'` latest
|
||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@@ -46,3 +46,7 @@ CMakeUserPresets.json
|
||||
# Conan
|
||||
*.pyc
|
||||
/test_package/build/
|
||||
|
||||
# cxxdraft-htmlgen
|
||||
docs/api_reference/src/source/
|
||||
docs/api_reference/gen/
|
||||
|
@@ -36,3 +36,5 @@ repos:
|
||||
rev: 5.0.4
|
||||
hooks:
|
||||
- id: flake8
|
||||
|
||||
exclude: ^docs/javascripts/
|
||||
|
368
CONTRIBUTING.md
368
CONTRIBUTING.md
@@ -1,93 +1,289 @@
|
||||
# Contributing to `mp-units`
|
||||
# Contributing
|
||||
|
||||
👍🎉 First off, thanks for taking the time to contribute! 🎉👍
|
||||
|
||||
## Gitpod
|
||||
|
||||
The easiest way to start coding is to jump straight into [Gitpod](https://www.gitpod.io). You can either click the button
|
||||
below or prefix any `mp-units` URL (main branch, other branches, issues, PRs, ...) in your web browser with `gitpod.io/#`
|
||||
(e.g., <https://gitpod.io/#https://github.com/mpusz/mp-units>).
|
||||
|
||||
[](https://gitpod.io/#https://github.com/mpusz/mp-units)
|
||||
|
||||
The above environment provides you with:
|
||||
|
||||
- all supported compilers for Linux development and the latest version of build tools like `cmake` and `conan`
|
||||
- all Conan dependencies preinstalled on the machine
|
||||
- all documentation generation tools ready to use
|
||||
- completed prebuilds for all targets (Debug and Release builds for each compiler)
|
||||
- VSCode preconfigured to benefit from all the above
|
||||
|
||||
## Download, Build, Install
|
||||
|
||||
Alternatively, please refer to our official docs for
|
||||
[download, build, and install instructions](https://mpusz.github.io/mp-units/latest/getting_started/installation_and_usage)
|
||||
if you want to setup a development environment on your local machine.
|
||||
|
||||
## Before Committing git Changes
|
||||
|
||||
There are a few steps recommended to check before committing and pushing your changes to the git repository.
|
||||
|
||||
### Naming Conventions
|
||||
|
||||
Here are the main rules for naming things in this repo:
|
||||
|
||||
- types, functions, variables naming in a `standard_case`
|
||||
- template parameters in a `PascalCase`
|
||||
- C++20 concepts names for now in a `PascalCase` but we plan to change it (see <https://github.com/mpusz/mp-units/issues/93>
|
||||
for more details)
|
||||
|
||||
### Unified Code Formatting
|
||||
|
||||
There is a formatting standard enforced with the `pre-commit` script. Before committing your changes please do the following:
|
||||
|
||||
```bash
|
||||
pip3 install -U pre-commit
|
||||
pre-commit run --all-files
|
||||
```
|
||||
|
||||
This will run `clang-format` for code formatting with the `.clang-format` file provided in the repo, `cmake-format` to format
|
||||
the CMake files, and some other check as well.
|
||||
The script will run on all the files in the repo and will apply the changes in-place when needed.
|
||||
After the script is done please make sure to stage all those changes to git commit.
|
||||
|
||||
### Build All CMake Targets And Run Unit Tests
|
||||
|
||||
The simplest way to verify if all targets build correctly and all unit tests pass is to run:
|
||||
|
||||
```bash
|
||||
conan build . -pr <your_conan_profile> -s compiler.cppstd=23 -o cxx_modules=True -c user.mp-units.build:all=True -b missing
|
||||
```
|
||||
|
||||
as described in the
|
||||
[Installation and Usage](https://mpusz.github.io/mp-units/latest/getting_started/installation_and_usage/#contributing-or-just-building-all-the-tests-and-examples)
|
||||
chapter of our documentation.
|
||||
|
||||
_Hint:_ To ensure that that we always build all the targets and to save some typing of the Conan commands,
|
||||
it is a good practice to set the following in the `~/.conan2/global.conf`:
|
||||
|
||||
```text
|
||||
user.mp-units.build:all=True
|
||||
```
|
||||
|
||||
Non-Conan users should:
|
||||
- build `all` and `all_verify_interface_header_sets` CMake targets,
|
||||
- run all unit tests.
|
||||
|
||||
### Backward Compatibility
|
||||
|
||||
Before submission, please remember to check if the code compiles fine on the supported compilers.
|
||||
The CI will check it anyway but it is good to check at least some of the configurations before pushing changes.
|
||||
Especially older compilers can be tricky as those do not support all the C++20 features well enough. The official
|
||||
list of supported compilers can be always found in the
|
||||
[Installation And Usage](https://mpusz.github.io/mp-units/latest/getting_started/cpp_compiler_support)
|
||||
chapter of our documentation.
|
||||
|
||||
|
||||
## Where To Start?
|
||||
## Where to start?
|
||||
|
||||
If you are looking for a good issue to start with, please check the following:
|
||||
|
||||
- [good first issue](https://github.com/mpusz/mp-units/labels/good%20first%20issue) - issues that should be pretty simple to implement.
|
||||
- [help wanted](https://github.com/mpusz/mp-units/labels/help%20wanted) - issues that typically are a bit more involved than beginner issues.
|
||||
- [high priority](https://github.com/mpusz/mp-units/labels/high%20priority) - things to fix ASAP but often of higher complexity.
|
||||
- [good first issue](https://github.com/mpusz/mp-units/labels/good%20first%20issue) - issues that
|
||||
should be pretty simple to implement,
|
||||
- [help wanted](https://github.com/mpusz/mp-units/labels/help%20wanted) - issues that typically are
|
||||
a bit more involved than beginner issues,
|
||||
- [high priority](https://github.com/mpusz/mp-units/labels/high%20priority) - things to fix ASAP
|
||||
but often of higher complexity.
|
||||
|
||||
|
||||
## Gitpod
|
||||
|
||||
The easiest way to start coding is to jump straight into [Gitpod](https://www.gitpod.io)
|
||||
environment. You can either click the button below
|
||||
|
||||
[](https://gitpod.io/#https://github.com/mpusz/mp-units)
|
||||
|
||||
or prefix any `mp-units` URL (main branch, other branches, issues, PRs, ...) in your web browser
|
||||
with `gitpod.io/#` (e.g., <https://gitpod.io/#https://github.com/mpusz/mp-units>).
|
||||
|
||||
The above environment provides you with:
|
||||
|
||||
- all supported compilers for Linux development and the latest version of build tools like `cmake`
|
||||
and `conan`,
|
||||
- all Conan dependencies preinstalled on the machine,
|
||||
- all documentation generation tools ready to use,
|
||||
- completed prebuilds for all targets (Debug and Release builds for each compiler),
|
||||
- VSCode preconfigured to benefit from all the above.
|
||||
|
||||
|
||||
## Building, testing, and packaging
|
||||
|
||||
Alternatively, please refer to our official docs for
|
||||
[download, build, and install instructions](https://mpusz.github.io/mp-units/latest/getting_started/installation_and_usage) with the below changes
|
||||
if you want to set up a development environment on your local machine.
|
||||
|
||||
|
||||
### Conan configuration properties
|
||||
|
||||
[`user.mp-units.build:all`](#user.mp-units.build-all){ #user.mp-units.build-all }
|
||||
|
||||
Enables compilation of all the source code, including tests and examples. To support this, it requires some additional Conan build dependencies described in
|
||||
[Repository directory tree and dependencies](https://mpusz.github.io/mp-units/latest/getting_started/project_structure#cmake-projects-and-dependencies).
|
||||
It also runs unit tests during the Conan build (unless
|
||||
[`tools.build:skip_test`](https://docs.conan.io/2/reference/commands/config.html?highlight=tools.build:skip_test#conan-config-list)
|
||||
configuration property is set to `True`).
|
||||
|
||||
[conan build all support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
[`user.mp-units.build:skip_la`](#user-skip-la){ #user-skip-la }
|
||||
|
||||
If `user.mp-units.build:all` is enabled, among others, Conan installs the external
|
||||
[wg21-linear_algebra](https://conan.io/center/recipes/wg21-linear_algebra)
|
||||
dependency and enables the compilation of linear algebra-based tests and usage examples.
|
||||
Such behavior can be disabled with this option.
|
||||
|
||||
[conan skip la support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
[`user.mp-units.analyze:clang-tidy`](#user.mp-units.analyze-clang-tidy){ #user.mp-units.analyze-clang-tidy }
|
||||
|
||||
Enables clang-tidy analysis.
|
||||
|
||||
[conan clang-tidy support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
|
||||
### CMake options for mp-units project developers
|
||||
|
||||
[`MP_UNITS_DEV_BUILD_LA`](#MP_UNITS_DEV_BUILD_LA){ #MP_UNITS_DEV_BUILD_LA }
|
||||
|
||||
: [:octicons-tag-24: 2.2.0][cmake build la support] · :octicons-milestone-24: `ON`/`OFF` (Default: `ON`)
|
||||
|
||||
Enables building code depending on the linear algebra library.
|
||||
|
||||
[cmake build la support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
[`MP_UNITS_DEV_IWYU`](#MP_UNITS_DEV_IWYU){ #MP_UNITS_DEV_IWYU }
|
||||
|
||||
: [:octicons-tag-24: 2.2.0][cmake iwyu support] · :octicons-milestone-24: `ON`/`OFF` (Default: `OFF`)
|
||||
|
||||
Enables include-what-you-use analysis.
|
||||
|
||||
[cmake iwyu support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
[`MP_UNITS_DEV_CLANG_TIDY`](#MP_UNITS_DEV_CLANG_TIDY){ #MP_UNITS_DEV_CLANG_TIDY }
|
||||
|
||||
: [:octicons-tag-24: 2.2.0][cmake clang-tidy support] · :octicons-milestone-24: `ON`/`OFF` (Default: `OFF`)
|
||||
|
||||
Enables clang-tidy analysis.
|
||||
|
||||
[cmake clang-tidy support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
|
||||
### Building the entire repository
|
||||
|
||||
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.mp-units.build:all`](#user.mp-units.build-all) = `True`.
|
||||
|
||||
```shell
|
||||
git clone https://github.com/mpusz/mp-units.git && cd units
|
||||
conan build . -pr <your_conan_profile> -s compiler.cppstd=23 -c user.mp-units.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 and testing:
|
||||
|
||||
```shell
|
||||
conan install . -pr <your_conan_profile> -s compiler.cppstd=23 -c user.mp-units.build:all=True -b missing
|
||||
cmake --preset conan-default
|
||||
cmake --build --preset conan-release
|
||||
cmake --build --preset conan-release --target all_verify_interface_header_sets
|
||||
cmake --build --preset conan-release --target test
|
||||
```
|
||||
|
||||
!!! hint
|
||||
|
||||
To ensure that we always build all the targets and to save some typing of the Conan commands,
|
||||
we can set the following in the `~/.conan2/global.conf`:
|
||||
|
||||
```text
|
||||
user.mp-units.build:all=True
|
||||
```
|
||||
|
||||
### Packaging
|
||||
|
||||
To test CMake installation and Conan packaging run:
|
||||
|
||||
```shell
|
||||
conan create . --user <username> --channel <channel> -pr <your_conan_profile> -s compiler.cppstd=23 \
|
||||
-c user.mp-units.build:all=True -b missing
|
||||
```
|
||||
|
||||
The above will create a Conan package and run tests provided in _./test_package_ directory.
|
||||
|
||||
In case you would like to upload **mp-units** package to the Conan server, do the following:
|
||||
|
||||
```shell
|
||||
conan upload -r <remote-name> --all mp-units/2.2.0@<user>/<channel>
|
||||
```
|
||||
|
||||
|
||||
## Building documentation
|
||||
|
||||
We are building our documentation using [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/).
|
||||
The easiest way to install all the required dependencies is with `pip`:
|
||||
|
||||
```shell
|
||||
pip install -U mkdocs-material mkdocs-rss-plugin
|
||||
```
|
||||
|
||||
Additionally, a [Cairo Graphics library](https://www.cairographics.org/) is required by
|
||||
Material for MkDocs. Please follow the
|
||||
[official MkDocs documentation to install it](https://squidfunk.github.io/mkdocs-material/plugins/requirements/image-processing/#cairo-graphics).
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
### Generating API reference
|
||||
|
||||
We need to take a few steps to set up our environment so that we are ready to generate API reference
|
||||
documents.
|
||||
|
||||
First, we need to satisfy the requirements described in <https://github.com/Eelis/cxxdraft-htmlgen>.
|
||||
On the Ubuntu platform, this is equivalent to the following instructions run from the user's home
|
||||
directory:
|
||||
|
||||
```bash
|
||||
sudo apt install haskell-stack graphviz nodejs npm ghc cabal-install
|
||||
npm install split mathjax-full mathjax-node-sre
|
||||
cabal update
|
||||
```
|
||||
|
||||
Also, installing `mathjax-node-cli` through npm does not help because `tex2html` is not called within
|
||||
node.js. This is why we need to download `mathjax-node-cli` and add its `bin` folder to the `PATH`
|
||||
environment variable:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/mathjax/mathjax-node-cli
|
||||
echo "export PATH=\"$PWD/mathjax-node-cli/bin:\$PATH\"" >> ~/.bashrc && source ~/.bashrc
|
||||
```
|
||||
|
||||
Next, we need to clone the following git repositories:
|
||||
|
||||
- <https://github.com/JohelEGP/jegp.cmake_modules>
|
||||
- `standardese_sources_base` branch of <https://github.com/JohelEGP/draft>
|
||||
- `standardese_sources_base` branch of <https://github.com/JohelEGP/cxxdraft-htmlgen>
|
||||
|
||||
For example:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/JohelEGP/jegp.cmake_modules.git --depth=1
|
||||
git clone https://github.com/JohelEGP/draft.git --branch=standardese_sources_base --depth=1
|
||||
git clone https://github.com/JohelEGP/cxxdraft-htmlgen.git --branch=standardese_sources_base --depth=1
|
||||
```
|
||||
|
||||
Now, we are ready to start building our API reference. First, we need to configure CMake with the
|
||||
following:
|
||||
|
||||
```bash
|
||||
cmake -S docs/api_reference/src -B build/docs/api_reference \
|
||||
-DCMAKE_MODULE_PATH="<path to gh:JohelEGP/jegp.cmake_modules>/modules" \
|
||||
-DJEGP_STANDARDESE_SOURCES_GIT_REPOSITORY="<path to gh:JohelEGP/draft>" \
|
||||
-DJEGP_CXXDRAFT_HTMLGEN_GIT_REPOSITORY="<path to gh:JohelEGP/cxxdraft-htmlgen>"
|
||||
```
|
||||
|
||||
Then we need to build the docs with CMake:
|
||||
|
||||
```bash
|
||||
cmake --build build/docs/api_reference
|
||||
```
|
||||
|
||||
In the end, we need to move the generated documentation to the `docs/api_reference/gen` subdirectory:
|
||||
|
||||
```bash
|
||||
mv build/docs/api_reference/mp-units.html docs/api_reference/gen
|
||||
```
|
||||
|
||||
or just link the entire directory:
|
||||
|
||||
```bash
|
||||
ln -sf ../../build/docs/api_reference/mp-units.html docs/api_reference/gen
|
||||
```
|
||||
|
||||
|
||||
## Before committing git changes
|
||||
|
||||
There are a few steps recommended to check before committing and pushing your changes to the git
|
||||
repository.
|
||||
|
||||
|
||||
### Naming conventions
|
||||
|
||||
Here are the main rules for naming things in this repo:
|
||||
|
||||
- types, functions, variables use `standard_case`,
|
||||
- template parameters use `PascalCase`,
|
||||
- C++ concept names, for now, use `PascalCase`, but we plan to change it
|
||||
(see [GitHub Issue #93](https://github.com/mpusz/mp-units/issues/93) for more details).
|
||||
|
||||
### Unified code formatting
|
||||
|
||||
A formatting standard is enforced with the `pre-commit` script. Before committing your changes,
|
||||
please do the following:
|
||||
|
||||
```bash
|
||||
pip install -U pre-commit
|
||||
pre-commit run --all-files
|
||||
```
|
||||
|
||||
This will run:
|
||||
|
||||
- `clang-format` for code formatting with the `.clang-format` file provided in the repo,
|
||||
- `cmake-format` to format the CMake files,
|
||||
- some other checks (e.g., python script checkers, whitespaces, etc.).
|
||||
|
||||
The script will run on all the files in the repo and will apply the changes in place when needed.
|
||||
After the script is done, please make sure to review and stage all those changes for the git commit.
|
||||
|
||||
### Backward compatibility
|
||||
|
||||
Before submission, please remember to check if the code compiles fine on the supported compilers.
|
||||
The CI will check it anyway, but it is good to check at least some of the configurations before
|
||||
pushing changes.
|
||||
Especially older compilers can be tricky as those do not have full C++20 conformance.
|
||||
The official list of supported compilers can always be found in the
|
||||
[C++ compiler support (API/ABI)](https://mpusz.github.io/mp-units/latest/getting_started/cpp_compiler_support)
|
||||
chapter of our documentation.
|
||||
|
@@ -0,0 +1,82 @@
|
||||
parse:
|
||||
additional_commands:
|
||||
_jegp_common_yaml_anchors:
|
||||
kwargs:
|
||||
PUBLIC_INTERFACE_PRIVATE: &public_interface_private
|
||||
kwargs:
|
||||
PUBLIC: +
|
||||
INTERFACE: +
|
||||
PRIVATE: +
|
||||
jegp_add_standardese_sources:
|
||||
pargs:
|
||||
nargs: 1
|
||||
flags:
|
||||
- EXCLUDE_FROM_ALL
|
||||
kwargs:
|
||||
LIBRARIES: +
|
||||
APPENDICES: +
|
||||
EXTENSIONS: +
|
||||
CHECKED: 1
|
||||
PDF: &standardese_pdf
|
||||
pargs:
|
||||
flags:
|
||||
- EXCLUDE_FROM_MAIN
|
||||
kwargs:
|
||||
PATH: 1
|
||||
HTML:
|
||||
<<: *standardese_pdf
|
||||
kwargs:
|
||||
SECTION_FILE_STYLE: 1
|
||||
LATEX_REGEX_REPLACE: +
|
||||
HTML_REGEX_REPLACE: +
|
||||
jegp_add_module:
|
||||
pargs: &jegp_add_module_pargs
|
||||
nargs: 1
|
||||
flags:
|
||||
- IMPORTABLE_HEADER
|
||||
kwargs:
|
||||
SOURCES: +
|
||||
COMPILE_OPTIONS: *public_interface_private
|
||||
LINK_LIBRARIES: *public_interface_private
|
||||
jegp_cpp_module:
|
||||
pargs: *jegp_add_module_pargs
|
||||
jegp_target_link_header_units:
|
||||
pargs:
|
||||
nargs: 1+
|
||||
jegp_cpp2_target_sources:
|
||||
pargs:
|
||||
nargs: 1
|
||||
kwargs:
|
||||
JEGP_FILE_SET_KWARGS: &file_set
|
||||
kwargs:
|
||||
FILE_SET: 1
|
||||
TYPE: 1
|
||||
BASE_DIRS: +
|
||||
FILES: +
|
||||
PUBLIC: *file_set
|
||||
INTERFACE: *file_set
|
||||
PRIVATE: *file_set
|
||||
jegp_add_headers_test:
|
||||
pargs:
|
||||
nargs: 1+
|
||||
kwargs:
|
||||
PRIVATE_REGEXES: +
|
||||
jegp_add_test:
|
||||
pargs:
|
||||
nargs: 1+
|
||||
flags:
|
||||
- COMPILE_ONLY
|
||||
kwargs:
|
||||
TYPE: 1
|
||||
SOURCES: +
|
||||
COMPILE_OPTIONS: +
|
||||
LINK_LIBRARIES: +
|
||||
jegp_add_build_error:
|
||||
pargs:
|
||||
nargs: 1+
|
||||
kwargs:
|
||||
AS: 1
|
||||
TYPE: 1
|
||||
SOURCE: 1
|
||||
COMPILE_OPTIONS: +
|
||||
LINK_LIBRARIES: +
|
74
docs/api_reference.md
Normal file
74
docs/api_reference.md
Normal file
@@ -0,0 +1,74 @@
|
||||
---
|
||||
hide:
|
||||
- navigation
|
||||
- toc
|
||||
---
|
||||
|
||||
<script src="../javascripts/jquery.min.js"></script>
|
||||
<script src="../javascripts/iframeResizer.min.js"></script>
|
||||
|
||||
<iframe id="apiIframe" style="width: 100%; border: none;"></iframe>
|
||||
|
||||
<script>
|
||||
// injects scripts to the iframe source code
|
||||
$('#apiIframe').on('load', function() {
|
||||
body = $(this).contents().find('body');
|
||||
body.append('<scr' + 'ipt src="../../javascripts/iframeResizer.contentWindow.min.js"></scr' + 'ipt>');
|
||||
body.append('<scr' + 'ipt>' +
|
||||
'var links = document.querySelectorAll("a");' +
|
||||
'for (var i = 0; i < links.length; i++) {' +
|
||||
' links[i].addEventListener("click", whichLinkWasClicked);' +
|
||||
'}' +
|
||||
'' +
|
||||
'function whichLinkWasClicked(evt) {' +
|
||||
' window.parentIFrame.sendMessage(evt.target.href);' +
|
||||
' evt.preventDefault();' +
|
||||
'}' +
|
||||
'</scr' + 'ipt>');
|
||||
});
|
||||
|
||||
// reloads the window with the content when a user navigates over the browser's history
|
||||
function locationHashChanged() {
|
||||
window.location.reload();
|
||||
}
|
||||
window.onhashchange = locationHashChanged;
|
||||
|
||||
apiIframe = document.getElementById('apiIframe');
|
||||
hash = window.location.hash;
|
||||
if (hash.length == 0) {
|
||||
// sets default hash for the API Reference
|
||||
hash = "#full";
|
||||
history.pushState(null, "", hash);
|
||||
}
|
||||
|
||||
// set the iframe source based on the hash in the URL
|
||||
if (hash.startsWith("#wg21.link/")) {
|
||||
apiIframe.src = "https://" + hash.slice(1);
|
||||
apiIframe.height = 900;
|
||||
}
|
||||
else
|
||||
apiIframe.src = "gen/" + hash.slice(1) + ".html";
|
||||
|
||||
// receives content height from the subpage displayed in the iframe
|
||||
// works only for the pages in the same domain as the main docs
|
||||
iFrameResize({
|
||||
scrolling: "yes",
|
||||
|
||||
// obtains the link URL clicked in the subpage
|
||||
onMessage: function(messageData) {
|
||||
url = messageData.message;
|
||||
if (url.startsWith("https://wg21.link/")) {
|
||||
hash = '#' + messageData.message.replace("https://", "");
|
||||
}
|
||||
else {
|
||||
pos = messageData.message.indexOf('#');
|
||||
if(pos == -1) {
|
||||
pos = messageData.message.lastIndexOf('/');
|
||||
}
|
||||
hash = '#' + messageData.message.slice(pos + 1);
|
||||
}
|
||||
history.pushState(null, "", hash);
|
||||
window.location.reload();
|
||||
}
|
||||
},'#apiIframe')
|
||||
</script>
|
41
docs/api_reference/src/CMakeLists.txt
Normal file
41
docs/api_reference/src/CMakeLists.txt
Normal file
@@ -0,0 +1,41 @@
|
||||
cmake_minimum_required(VERSION 3.24.0)
|
||||
project(mp-units_reference_documentations LANGUAGES NONE)
|
||||
|
||||
include(JEGPAddStandardeseSources)
|
||||
|
||||
set(pdf_title "mp-units Library")
|
||||
set(page_license "MIT License")
|
||||
set(first_library_chapter "qties")
|
||||
set(last_library_chapter "qties")
|
||||
set(cover_title "mp-units Library Reference Documentations")
|
||||
set(reply_to "\\href{${PROJECT_HOMEPAGE_URL}/discussions}{Discussions}, \\href{${PROJECT_HOMEPAGE_URL}/issues}{issues}")
|
||||
jegp_add_standardese_sources(
|
||||
mp-units_reference_documentations
|
||||
LIBRARIES intro quantities
|
||||
EXTENSIONS macros_extensions
|
||||
CHECKED TRUE
|
||||
# PDF PATH "mp-units.pdf" #[[EXCLUDE_FROM_MAIN]]
|
||||
HTML PATH "mp-units.html" #[[EXCLUDE_FROM_MAIN]]
|
||||
SECTION_FILE_STYLE "WithExtension"
|
||||
LATEX_REGEX_REPLACE
|
||||
# Latex commands.
|
||||
[[\\href{([^}]+)}{([^}]+)};HREF(\1)(\2)]]
|
||||
# Macros extensions.
|
||||
[[\\refcpp{([^}]+)};REFCPP(\1)]]
|
||||
[[\\irefcpp{([^}]+)};~(REFCPP(\1))]]
|
||||
[[\\refcppx{([^}]+)}{([^}]+)};REFCPPX(\1)(\2)]]
|
||||
[[\\irefcppx{([^}]+)}{([^}]+)};~(REFCPPX(\1)(\2))]]
|
||||
[[\\refiev{([^}]+)};REFIEV(\1)]]
|
||||
[[\\irefiev{([^}]+)};~(REFIEV(\1))]]
|
||||
# Main matter and annexes.
|
||||
[[\\\"{o};ö]]
|
||||
HTML_REGEX_REPLACE
|
||||
# Latex commands.
|
||||
[[HREF\(([^)]+)\)\(([^)]+)\);<a href="\1">\2</a>]]
|
||||
# Macros extensions.
|
||||
[[REFCPP\(([^)]+)\);<a href="https://wg21.link/\1">ISOCPP, [\1]</a>]]
|
||||
[[REFCPPX\(([^)]+)\)\(([^)]+)\);<a href="https://wg21.link/\1\2">ISOCPP, [\1]</a>]] #
|
||||
[[ISOCPP;N4971]]
|
||||
[[REFIEV\(([^)]+)\);<a href="https://www.electropedia.org/iev/iev.nsf/display?openform&ievref=\1">IEC 60050, \1</a>]]
|
||||
# Main matter and annexes.
|
||||
)
|
134
docs/api_reference/src/intro.tex
Normal file
134
docs/api_reference/src/intro.tex
Normal file
@@ -0,0 +1,134 @@
|
||||
%!TEX root = std.tex
|
||||
|
||||
|
||||
\rSec0[scope]{Scope}
|
||||
|
||||
\pnum
|
||||
\indextext{scope|(}%
|
||||
This document describes the contents of the \defn{mp-units library}.
|
||||
\indextext{scope|)}
|
||||
|
||||
|
||||
\rSec0[refs]{References}
|
||||
|
||||
\pnum
|
||||
\indextext{references|(}%
|
||||
The following documents are referred to in the text
|
||||
in such a way that some or all of their content
|
||||
constitutes requirements of this document.
|
||||
For dated references, only the edition cited applies.
|
||||
For undated references,
|
||||
the latest edition of the referenced document
|
||||
(including any amendments) applies.
|
||||
\begin{itemize}
|
||||
\item
|
||||
IEC 60050-102:2007/AMD3:2021,
|
||||
\doccite{Amendment 3 --- International Electrotechnical Vocabulary (IEV) ---
|
||||
Part 102: Mathematics --- General concepts and linear algebra}
|
||||
\item
|
||||
IEC 60050-112:2010/AMD2:2020,
|
||||
\doccite{Amendment 2 --- International Electrotechnical Vocabulary (IEV) ---
|
||||
Part 112: Quantities and units}
|
||||
\item
|
||||
ISO 80000 (all parts), \doccite{Quantities and units}
|
||||
\item
|
||||
The \Cpp{} Standards Committee.
|
||||
\IsoCpp{}: \doccite{Working Draft, Standard for Programming Language \Cpp{}}.
|
||||
Edited by Thomas K\"{o}ppe.
|
||||
Available from: \url{https://wg21.link/\IsoCpp{}}
|
||||
\item
|
||||
The \Cpp{} Standards Committee.
|
||||
SD-8: \doccite{Standard Library Compatibility}.
|
||||
Edited by Bryce Lelbach.
|
||||
Available from: \url{https://wg21.link/SD8}
|
||||
\end{itemize}
|
||||
\indextext{references|)}
|
||||
|
||||
|
||||
\rSec0[defs]{Terms and definitions}
|
||||
|
||||
\pnum
|
||||
\indextext{definitions|(}%
|
||||
For the purposes of this document,
|
||||
the terms and definitions given in
|
||||
IEC 60050-102:2007/AMD3:2021,
|
||||
IEC 60050-112:2010/AMD2:2020,
|
||||
ISO 80000-2:2019,
|
||||
and
|
||||
\IsoCpp{},
|
||||
and the following apply.
|
||||
|
||||
\pnum
|
||||
ISO and IEC maintain terminology databases
|
||||
for use in standardization
|
||||
at the following addresses:
|
||||
\begin{itemize}
|
||||
\item ISO Online browsing platform: available at \url{https://www.iso.org/obp}
|
||||
\item IEC Electropedia: available at \url{http://www.electropedia.org}
|
||||
\end{itemize}
|
||||
\indextext{definitions|)}
|
||||
|
||||
|
||||
\rSec0[spec]{Specification}
|
||||
|
||||
\rSec1[spec.ext]{External}
|
||||
|
||||
\pnum
|
||||
The specification of the mp-units library subsumes
|
||||
\refcpp{description}, \refcpp{requirements}, \refcpp{concepts.equality}, and SD-8,
|
||||
all assumingly amended for the context of this library.
|
||||
\begin{note}
|
||||
This means that, non exhaustively,
|
||||
\begin{itemize}
|
||||
\item \tcode{::mp_units2} is a reserved namespace, and
|
||||
\item
|
||||
\tcode{std::vector<mp_units::\placeholdernc{type}>}
|
||||
is a program-defined specialization and a library-defined specialization
|
||||
from the point of view of the \Cpp{} standard library and the mp-units library, respectively.
|
||||
\end{itemize}
|
||||
\end{note}
|
||||
|
||||
\pnum
|
||||
The mp-units library is not part of the \Cpp{} implementation.
|
||||
|
||||
\rSec1[spec.cats]{Categories}
|
||||
|
||||
\pnum
|
||||
Detailed specifications for each of the components in the library are in
|
||||
\ref{\firstlibchapter}--\ref{\lastlibchapter},
|
||||
as shown in \tref{lib.cats}.
|
||||
|
||||
\begin{floattable}{Library categories}{lib.cats}
|
||||
{ll}
|
||||
\topline
|
||||
\hdstyle{Clause} & \hdstyle{Category} \\ \capsep
|
||||
\ref{qties} & Quantities library \\
|
||||
\end{floattable}
|
||||
|
||||
\pnum
|
||||
The quantities library\iref{qties}
|
||||
describes components for dealing with quantities.
|
||||
|
||||
\rSec1[spec.mods]{Modules}
|
||||
|
||||
\pnum
|
||||
The mp-units library provides the
|
||||
\defnx{mp-units modules}{module!mp-units},
|
||||
shown in \tref{modules}.
|
||||
|
||||
\begin{multicolfloattable}{mp-units modules}{modules}
|
||||
{lll}
|
||||
\tcode{mp_units} \\
|
||||
\columnbreak
|
||||
\tcode{mp_units.core} \\
|
||||
\columnbreak
|
||||
\tcode{mp_units.systems} \\
|
||||
\end{multicolfloattable}
|
||||
|
||||
\rSec1[spec.reqs]{Library-wide requirements}
|
||||
|
||||
\rSec2[spec.res.names]{Reserved names}
|
||||
|
||||
\pnum
|
||||
The mp-units library reserves macro names that start with
|
||||
\tcode{MP_UNITS\opt{\gterm{digit-sequence}}_}.
|
11
docs/api_reference/src/macros_extensions.tex
Normal file
11
docs/api_reference/src/macros_extensions.tex
Normal file
@@ -0,0 +1,11 @@
|
||||
\newcommand{\IsoCpp}{N4971}
|
||||
|
||||
%% Inline non-parenthesized C++ reference
|
||||
\newcommand{\refcpp}[1]{\href{https://wg21.link/#1}{\IsoCpp{}, [#1]}}
|
||||
\newcommand{\irefcpp}[1]{\nolinebreak[3] (\refcpp{#1})}
|
||||
\newcommand{\refcppx}[2]{\href{https://wg21.link/#1\##2}{\IsoCpp{}, [#1]}}
|
||||
\newcommand{\irefcppx}[2]{\nolinebreak[3] (\refcppx{#1}{#2})}
|
||||
|
||||
%% Inline IEV reference
|
||||
\newcommand{\refiev}[1]{\href{https://www.electropedia.org/iev/iev.nsf/display?openform&ievref=#1}{IEC 60050, #1}}
|
||||
\newcommand{\irefiev}[1]{\nolinebreak[3] (\refiev{#1})}
|
266
docs/api_reference/src/quantities.tex
Normal file
266
docs/api_reference/src/quantities.tex
Normal file
@@ -0,0 +1,266 @@
|
||||
%!TEX root = std.tex
|
||||
\rSec0[qties]{Quantities library}
|
||||
|
||||
\rSec1[qties.summary]{Summary}
|
||||
|
||||
\pnum
|
||||
This Clause describes components for dealing with quantities,
|
||||
as summarized in \tref{qties.summary}.
|
||||
|
||||
\begin{modularlibsumtab}{Quantities library summary}{qties.summary}
|
||||
\ref{qty.helpers} & Helpers & \tcode{mp_units.core} \\
|
||||
\ref{qty.traits} & Traits & \\
|
||||
\ref{qty.concepts} & Concepts & \\
|
||||
\ref{qty.types} & Types & \\
|
||||
\ref{qty.compat} & Compatibility & \\
|
||||
\ref{qty.one} & Dimension one & \\ \rowsep
|
||||
\ref{qty.systems} & Systems & \tcode{mp_units.systems} \\
|
||||
\ref{qty.chrono} & \tcode{std::chrono} compatibility & \\
|
||||
\end{modularlibsumtab}
|
||||
|
||||
\rSec1[mp.units.syn]{Module \tcode{mp_units} synopsis}
|
||||
\indexmodule{mp_units}%
|
||||
\begin{codeblock}
|
||||
export module mp_units;
|
||||
|
||||
export import mp_units.core;
|
||||
export import mp_units.systems;
|
||||
\end{codeblock}
|
||||
|
||||
\rSec1[mp.units.core.syn]{Module \tcode{mp_units.core} synopsis}
|
||||
\indexmodule{mp_units.core}%
|
||||
\begin{codeblock}
|
||||
export module mp_units.core;
|
||||
|
||||
import std;
|
||||
|
||||
export namespace mp_units {
|
||||
|
||||
export enum class quantity_character { scalar, vector, tensor };
|
||||
|
||||
// \ref{qty.traits}, traits
|
||||
|
||||
template<typename Rep>
|
||||
constexpr bool treat_as_floating_point = std::is_floating_point_v<Rep>;
|
||||
|
||||
template<typename Rep>
|
||||
constexpr bool is_scalar =
|
||||
std::is_floating_point_v<Rep> || (std::is_integral_v<Rep> && !is_same_v<Rep, bool>);
|
||||
|
||||
template<typename Rep>
|
||||
constexpr bool is_vector = false;
|
||||
|
||||
template<typename Rep>
|
||||
constexpr bool is_tensor = false;
|
||||
|
||||
template<typename Rep>
|
||||
struct quantity_values;
|
||||
|
||||
template<typename T>
|
||||
struct quantity_like_traits;
|
||||
|
||||
template<typename T>
|
||||
struct quantity_point_like_traits;
|
||||
|
||||
// \ref{qty.concepts}, concepts
|
||||
|
||||
template<typename T>
|
||||
concept @\deflibconcept{some_reference}@ = template_of(^std::remove_cvref_t<T>) == ^reference;
|
||||
|
||||
template<typename T>
|
||||
concept representation = @\seebelownc@;
|
||||
|
||||
template<typename T, quantity_character Ch>
|
||||
concept representation_of = @\seebelownc@;
|
||||
|
||||
template<typename T>
|
||||
concept some_quantity_spec = @\seebelownc@;
|
||||
|
||||
// \ref{qty.types}, types
|
||||
|
||||
template<auto...>
|
||||
struct quantity_spec; // \notdef
|
||||
|
||||
template<auto Q>
|
||||
struct kind_of_; // \notdef
|
||||
|
||||
template<@\unspec@... Expr>
|
||||
struct derived_quantity_spec;
|
||||
|
||||
// \ref{qty.type}, class template \tcode{quantity}
|
||||
export template<@\libconcept{some_reference}@ auto R,
|
||||
@\libconcept{representation_of}@<get_quantity_spec(R).character> Rep = double>
|
||||
class quantity;
|
||||
|
||||
// \ref{qty.point.type}, class template \tcode{quantity_point}
|
||||
template<@\unspec@>
|
||||
class quantity_point;
|
||||
|
||||
}
|
||||
\end{codeblock}
|
||||
|
||||
\rSec1[mp.units.systems.syn]{Module \tcode{mp_units.systems} synopsis}
|
||||
\indexmodule{mp_units.systems}%
|
||||
\begin{codeblock}
|
||||
export module mp_units.systems;
|
||||
|
||||
export import mp_units.core;
|
||||
import std;
|
||||
|
||||
export namespace mp_units {
|
||||
|
||||
}
|
||||
\end{codeblock}
|
||||
|
||||
\rSec1[qty.helpers]{Helpers}
|
||||
|
||||
\begin{itemdecl}
|
||||
consteval bool @\exposidnc{converts-to-base-subobject-of}@(std::meta type, std::meta template_name);
|
||||
\end{itemdecl}
|
||||
|
||||
\begin{itemdescr}
|
||||
\pnum
|
||||
\expects
|
||||
\tcode{is_type(type) \&\& is_template(template_name)} is \tcode{true}.
|
||||
|
||||
\pnum
|
||||
\returns
|
||||
\tcode{true} if
|
||||
\tcode{[:type:]} has an unambiguous and accessible base
|
||||
that is a specialization of \tcode{[:template_name:]}, and
|
||||
\tcode{false} otherwise.
|
||||
\end{itemdescr}
|
||||
|
||||
\rSec1[qty.traits]{Traits}
|
||||
|
||||
\begin{itemdecl}
|
||||
template<typename Rep>
|
||||
constexpr bool @\libglobal{is_scalar}@ =
|
||||
std::is_floating_point_v<Rep> || (std::is_integral_v<Rep> && !is_same_v<Rep, bool>);
|
||||
|
||||
template<typename Rep>
|
||||
constexpr bool @\libglobal{is_vector}@ = false;
|
||||
|
||||
template<typename Rep>
|
||||
constexpr bool @\libglobal{is_tensor}@ = false;
|
||||
\end{itemdecl}
|
||||
|
||||
\begin{itemdescr}
|
||||
\pnum
|
||||
\remarks
|
||||
Pursuant to \refcpp{namespace.std}\iref{spec.ext},
|
||||
users may specialize \tcode{is_scalar}, \tcode{is_vector}, and \tcode{is_tensor} to \tcode{true}
|
||||
for cv-unqualified program-defined types
|
||||
which respectively represent
|
||||
a scalar\irefiev{102-02-18},
|
||||
a vector\irefiev{102-03-04}, and
|
||||
% FIXME Undefined term.
|
||||
a tensor,
|
||||
and \tcode{false} for types which respectively do not.
|
||||
\end{itemdescr}
|
||||
|
||||
\rSec1[qty.concepts]{Concepts}
|
||||
|
||||
\begin{itemdecl}
|
||||
export template<typename T>
|
||||
concept @\deflibconcept{representation}@ =
|
||||
(is_scalar<T> || is_vector<T> || is_tensor<T>)&&std::regular<T> && @\exposidnc{scalable}@<T>;
|
||||
\end{itemdecl}
|
||||
|
||||
\begin{itemdecl}
|
||||
export template<typename T, quantity_character Ch>
|
||||
concept @\deflibconcept{representation_of}@ =
|
||||
@\libconcept{representation}@<T> && ((Ch == quantity_character::scalar && is_scalar<T>) ||
|
||||
(Ch == quantity_character::vector && is_vector<T>) ||
|
||||
(Ch == quantity_character::tensor && is_tensor<T>));
|
||||
\end{itemdecl}
|
||||
|
||||
% FIXME Despite the `some_` prefix, it doesn't conform to the convention
|
||||
% `template_of(^std::remove_cvref_t<T>) == ^template_name`.
|
||||
\begin{itemdecl}
|
||||
template<typename T>
|
||||
concept @\defexposconceptnc{named-quantity-spec}@ =
|
||||
(@\exposidnc{converts-to-base-subobject-of}@(^T, ^quantity_spec) && template_of(^T) != ^kind_of_);
|
||||
|
||||
template<typename T>
|
||||
concept @\deflibconcept{some_quantity_spec}@ =
|
||||
@\exposconceptnc{named-quantity-spec}@<T> ||
|
||||
detail::IntermediateDerivedQuantitySpec<T> ||
|
||||
template_of(^T) == ^kind_of;
|
||||
\end{itemdecl}
|
||||
|
||||
\rSec1[qty.types]{Types}
|
||||
|
||||
\rSec2[qty.types.general]{General}
|
||||
|
||||
\pnum
|
||||
A \defnadj{quantity}{type}
|
||||
is a type \tcode{\placeholder{Q}}
|
||||
that is a specialization of \tcode{quantity} or \tcode{quantity_point}.
|
||||
\tcode{\placeholder{Q}} represents a quantity\irefiev{112-01-01}
|
||||
with \tcode{\placeholder{Q}::rep} as its number
|
||||
and \tcode{\placeholder{Q}::reference} as its reference.
|
||||
\tcode{\placeholder{Q}} is a structural type\irefcppx{temp.param}{term.structural.type}
|
||||
if \tcode{\placeholder{Q}::rep} is a structural type.
|
||||
|
||||
\pnum
|
||||
Each class template defined in subclause \ref{qty.types}
|
||||
has data members and special members specified below, and
|
||||
has no base classes or members other than those specified.
|
||||
|
||||
\rSec2[qty.type]{Class template \tcode{quantity}}
|
||||
|
||||
\begin{codeblock}
|
||||
namespace mp_units {
|
||||
|
||||
export template<@\libconcept{some_reference}@ auto R,
|
||||
@\libconcept{representation_of}@<get_quantity_spec(R).character> Rep = double>
|
||||
class quantity { @\unspec@ };
|
||||
|
||||
}
|
||||
\end{codeblock}
|
||||
|
||||
Let \tcode{\placeholder{Q}} be a specialization of \tcode{quantity}.
|
||||
\begin{itemize}
|
||||
\item
|
||||
If \tcode{Rep} is a scalar,
|
||||
\tcode{\placeholder{Q}} represents a scalar quantity\irefiev{102-02-19}.
|
||||
\item
|
||||
If \tcode{Rep} is a vector,
|
||||
\tcode{\placeholder{Q}} represents a vector\irefiev{102-03-04}.
|
||||
% FIXME What if `Rep` is a tensor?
|
||||
\end{itemize}
|
||||
|
||||
\rSec2[qty.point.type]{Class template \tcode{quantity_point}}
|
||||
|
||||
\begin{codeblock}
|
||||
namespace mp_units {
|
||||
|
||||
export template<@\unspec@>
|
||||
class quantity_point { @\unspec@ };
|
||||
|
||||
}
|
||||
\end{codeblock}
|
||||
|
||||
A \defnadj{quantity point}{type} is a specialization of \tcode{quantity_point}.
|
||||
Let \tcode{\placeholder{Q}} be a quantity point type.
|
||||
\tcode{\placeholdernc{Q}::point_origin} represents
|
||||
the origin point of a position vector\irefiev{102-03-15}.
|
||||
\begin{itemize}
|
||||
\item
|
||||
If \tcode{Rep} is a scalar,
|
||||
\tcode{\placeholder{Q}} represents the scalar quantity\irefiev{102-02-19}
|
||||
of a position vector.
|
||||
\item
|
||||
If \tcode{Rep} is a vector,
|
||||
\tcode{\placeholder{Q}} represents a position vector.
|
||||
% FIXME What if `Rep` is a tensor?
|
||||
\end{itemize}
|
||||
|
||||
\rSec1[qty.compat]{Compatibility}
|
||||
|
||||
\rSec1[qty.one]{Dimension one}
|
||||
|
||||
\rSec1[qty.systems]{Systems}
|
||||
|
||||
\rSec1[qty.chrono]{\tcode{std::chrono} compatibility}
|
1
docs/getting_started/contributing.md
Symbolic link
1
docs/getting_started/contributing.md
Symbolic link
@@ -0,0 +1 @@
|
||||
../../CONTRIBUTING.md
|
@@ -1,155 +1,7 @@
|
||||
# Installation And Usage
|
||||
|
||||
This chapter provides all the necessary information to obtain and build the code using **mp-units**.
|
||||
It also describes how to build or distribute the library and generate its documentation.
|
||||
|
||||
|
||||
## Project structure
|
||||
|
||||
### Repository directory tree and dependencies
|
||||
|
||||
The [GitHub repository](https://github.com/mpusz/mp-units) 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) or [ms-gsl](https://github.com/microsoft/GSL)
|
||||
to verify runtime contracts (if contract checking is enabled),
|
||||
- [{fmt}](https://github.com/fmtlib/fmt) to provide text formatting of quantities
|
||||
(if `std::format` is not supported yet on a specific compiler).
|
||||
|
||||
- **_._**
|
||||
|
||||
- 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.
|
||||
|
||||
- **_./test_package_**
|
||||
|
||||
- CMake library installation and Conan package verification.
|
||||
|
||||
|
||||
!!! important "Important: Library users should not use the top-level CMake file"
|
||||
|
||||
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()`](https://cmake.org/cmake/help/latest/command/add_subdirectory.html) to
|
||||
handle the dependencies.
|
||||
|
||||
To learn more about the rationale, please check our
|
||||
[FAQ](faq.md#why-dont-we-have-cmake-options-to-disable-the-building-of-tests-and-examples).
|
||||
|
||||
### Modules
|
||||
|
||||
The **mp-units** library provides the following C++ modules:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
mp_units --- mp_units.systems --- mp_units.core
|
||||
```
|
||||
|
||||
| C++ Module | CMake Target | Contents |
|
||||
|--------------------|----------------------|----------------------------------------------------------|
|
||||
| `mp_units.core` | `mp-units::core` | Core library framework and systems-independent utilities |
|
||||
| `mp_units.systems` | `mp-units::systems` | All the systems of quantities and units |
|
||||
| `mp_units` | `mp-units::mp-units` | Core + Systems |
|
||||
|
||||
!!! note
|
||||
|
||||
C++ modules are provided within the package only when:
|
||||
|
||||
- [`cxx_modules`](#cxx_modules) Conan option is set to `True`,
|
||||
- [`MP_UNITS_BUILD_CXX_MODULES`](#MP_UNITS_BUILD_CXX_MODULES) CMake option is set to `ON`.
|
||||
|
||||
### Header files
|
||||
|
||||
All of the project's header files can be found in the `mp-units/...` subdirectory.
|
||||
|
||||
#### Core library
|
||||
|
||||
- `mp-units/framework.h` contains the entire library's framework definitions,
|
||||
- `mp-units/concepts.h` exposes only the library's concepts for generic code needs,
|
||||
- `mp-units/format.h` provides text formatting support,
|
||||
- `mp-units/ostream.h` enables streaming of the library's objects to the text output,
|
||||
- `mp-units/math.h` provides overloads of common math functions for quantities,
|
||||
- `mp-units/random.h` provides C++ pseudo-random number generators for quantities,
|
||||
- `mp-units/compat_macros.h` provides macros for [wide compatibility](../users_guide/use_cases/wide_compatibility.md).
|
||||
|
||||
??? info "More details"
|
||||
|
||||
More detailed header files can be found in subfolders which typically should not be
|
||||
included by the end users:
|
||||
|
||||
- `mp-units/framework/...` provides all the public interfaces of the framework,
|
||||
- `mp-units/bits/...` provides private implementation details only (no public definitions),
|
||||
- `mp-units/ext/...` contains external dependencies that at some point in the future should
|
||||
be replaced with C++ standard library facilities.
|
||||
|
||||
#### Systems and associated utilities
|
||||
|
||||
The systems definitions can be found in the `mp-units/systems/...` subdirectory:
|
||||
|
||||
##### Systems of quantities
|
||||
|
||||
- `mp-units/systems/isq.h` provides
|
||||
[International System of Quantities (ISQ)](https://en.wikipedia.org/wiki/International_System_of_Quantities)
|
||||
definitions,
|
||||
|
||||
??? tip "Tip: Improving compile times"
|
||||
|
||||
`mp-units/systems/isq.h` might be expensive to compile in every translation unit. There are
|
||||
some smaller, domain targeted files available for explicit inclusion in the
|
||||
`mp-units/systems/isq/...` subdirectory.
|
||||
|
||||
##### Systems of units
|
||||
|
||||
- `mp-units/systems/si.h` provides
|
||||
[International System of Units (SI)](https://en.wikipedia.org/wiki/International_System_of_Units)
|
||||
definitions and associated math functions,
|
||||
- `mp-units/systems/angular.h` provides strong angular units and associated math functions,
|
||||
- `mp-units/systems/international.h` provides
|
||||
[international yard and pound](https://en.wikipedia.org/wiki/International_yard_and_pound) units,
|
||||
- `mp-units/systems/imperial.h` includes `international.h` and extends it with
|
||||
[imperial units](https://en.wikipedia.org/wiki/Imperial_units),
|
||||
- `mp-units/systems/usc.h` includes `international.h` and extends it with
|
||||
[United States customary system of units](https://en.wikipedia.org/wiki/United_States_customary_units),
|
||||
- `mp-units/systems/cgs.h` provides
|
||||
[centimetre-gram-second system of units](https://en.wikipedia.org/wiki/Centimetre%E2%80%93gram%E2%80%93second_system_of_units),
|
||||
- `mp-units/systems/iau.h` provides
|
||||
[astronomical system of units](https://en.wikipedia.org/wiki/Astronomical_system_of_units),
|
||||
- `mp-units/systems/hep.h` provides units used in
|
||||
[high-energy physics](https://en.wikipedia.org/wiki/Particle_physics),
|
||||
- `mp-units/systems/typographic.h` provides units used in
|
||||
[typography or typesetting](https://en.wikipedia.org/wiki/Typographic_unit),
|
||||
- `mp-units/systems/natural.h` provides an example implementation of
|
||||
[natural units](https://en.wikipedia.org/wiki/Natural_units).
|
||||
|
||||
??? tip "Tip: Improving compile times"
|
||||
|
||||
`mp-units/systems/si.h` might be expensive to compile in every translation unit.
|
||||
There are some smaller files available for explicit inclusion in the
|
||||
`mp-units/systems/si/...` subdirectory.
|
||||
|
||||
`mp-units/systems/si/unit_symbols.h` is the most expensive to include.
|
||||
This chapter provides all the necessary information to obtain **mp-units** and build the user's
|
||||
source code using it.
|
||||
|
||||
|
||||
## Obtaining dependencies
|
||||
@@ -157,66 +9,82 @@ The systems definitions can be found in the `mp-units/systems/...` subdirectory:
|
||||
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
|
||||
??? info "Conan quick intro"
|
||||
|
||||
In case you are not familiar with Conan, to install it (or upgrade) just do:
|
||||
In case you are not familiar with Conan, to install it (or upgrade) just do:
|
||||
|
||||
```shell
|
||||
pip 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 "Setting the language version"
|
||||
|
||||
Please note that the **mp-units** library requires at least C++20 to be set in a Conan profile
|
||||
or forced via the Conan command line. If we do the former, we will not need to provide
|
||||
`-s compiler.cppstd=20` every time we run a Conan command line (as provided in the command
|
||||
line instructions below).
|
||||
|
||||
!!! tip "Using Ninja as a CMake generator for Conan"
|
||||
|
||||
It is highly recommended to set Ninja as a CMake generator for Conan. To do so, we should
|
||||
create a _~/.conan2/global.conf_ file that will set `tools.cmake.cmaketoolchain:generator`
|
||||
to one of the Ninja generators. For example:
|
||||
|
||||
```text title="~/.conan2/global.conf"
|
||||
tools.cmake.cmaketoolchain:generator="Ninja Multi-Config"
|
||||
```shell
|
||||
pip install -U conan
|
||||
```
|
||||
|
||||
!!! tip "Separate build folders for different configurations"
|
||||
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:
|
||||
|
||||
_~/.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 and C++ standard version:
|
||||
```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
|
||||
|
||||
```text title="~/.conan2/global.conf"
|
||||
tools.cmake.cmake_layout:build_folder_vars=["settings.compiler", "settings.compiler.version", "settings.compiler.cppstd"]
|
||||
[conf]
|
||||
tools.build:compiler_executables={"c": "gcc-12", "cpp": "g++-12"}
|
||||
```
|
||||
|
||||
In such a case, we will need to use a configuration-specific preset name in the Conan instructions
|
||||
provided below rather than just `conan-default` and `conan-release`
|
||||
(e.g. `conan-gcc-13-23` and `conan-gcc-13-23-release`)
|
||||
!!! tip "Setting the language version"
|
||||
|
||||
Please note that the **mp-units** library requires at least C++20 to be set in a Conan profile
|
||||
or forced via the Conan command line. If we do the former, we will not need to provide
|
||||
`-s compiler.cppstd=20` every time we run a Conan command line (as provided in the command
|
||||
line instructions below).
|
||||
|
||||
!!! tip "Using Ninja as a CMake generator for Conan"
|
||||
|
||||
It is highly recommended to set Ninja as a CMake generator for Conan. To do so, we could
|
||||
create a _~/.conan2/global.conf_ file that will set `tools.cmake.cmaketoolchain:generator`
|
||||
to one of the Ninja generators. For example:
|
||||
|
||||
```text title="~/.conan2/global.conf"
|
||||
tools.cmake.cmaketoolchain:generator="Ninja Multi-Config"
|
||||
```
|
||||
|
||||
!!! tip "Separate build folders for different configurations"
|
||||
|
||||
_~/.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 and C++ standard version:
|
||||
|
||||
```text title="~/.conan2/global.conf"
|
||||
tools.cmake.cmake_layout:build_folder_vars=["settings.compiler", "settings.compiler.version", "settings.compiler.cppstd"]
|
||||
```
|
||||
|
||||
In such a case, we will need to use a configuration-specific preset name in the Conan instructions
|
||||
provided below rather than just `conan-default` and `conan-release`
|
||||
(e.g., `conan-gcc-13-23` and `conan-gcc-13-23-release`)
|
||||
|
||||
??? info "CMake with presets support"
|
||||
|
||||
It is recommended to use at least CMake 3.23 to build this project to benefit from CMake Presets
|
||||
generated by Conan. 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
|
||||
```
|
||||
|
||||
!!! tip
|
||||
|
||||
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.
|
||||
|
||||
|
||||
## Build options
|
||||
@@ -225,7 +93,7 @@ tools.build:compiler_executables={"c": "gcc-12", "cpp": "g++-12"}
|
||||
|
||||
Most of the below options are related to the C++ language features available in the compilers.
|
||||
Please refer to the [C++ compiler support](cpp_compiler_support.md) chapter to learn more
|
||||
about which C++ features are required and which compiler support them.
|
||||
about which C++ features are required for each option and which compilers support them.
|
||||
|
||||
### Conan options
|
||||
|
||||
@@ -289,166 +157,92 @@ tools.build:compiler_executables={"c": "gcc-12", "cpp": "g++-12"}
|
||||
: [:octicons-tag-24: 2.2.0][conan freestanding] · :octicons-milestone-24: `True`/`False` (Default: `False`)
|
||||
|
||||
Configures the library in the [freestanding](https://en.cppreference.com/w/cpp/freestanding)
|
||||
mode. When enabled, the library's source code should build with the compiler's
|
||||
mode. When enabled, the library's source code will build with the compiler's
|
||||
[`-ffreestanding`](https://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html) compilation option
|
||||
without any issues.
|
||||
|
||||
[conan freestanding]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
### Conan configuration properties
|
||||
??? info "CMake options to set when Conan is not being used"
|
||||
|
||||
[`user.mp-units.build:all`](#user.mp-units.build-all){ #user.mp-units.build-all }
|
||||
### CMake options
|
||||
|
||||
: [:octicons-tag-24: 2.2.0][conan build all support] · :octicons-milestone-24: `True`/`False` (Default: `False`)
|
||||
Conan will automatically set all the below CMake options based on its configuration (described above).
|
||||
Manual setting of the below CMake options is only needed when Conan is not being used.
|
||||
|
||||
Enables compilation of all the source code, including tests and examples. To support this, it requires some additional Conan build dependencies described in
|
||||
[Repository directory tree and dependencies](#repository-directory-tree-and-dependencies).
|
||||
It also runs unit tests during Conan build (unless
|
||||
[`tools.build:skip_test`](https://docs.conan.io/2/reference/commands/config.html?highlight=tools.build:skip_test#conan-config-list)
|
||||
configuration property is set to `True`).
|
||||
[`MP_UNITS_BUILD_AS_SYSTEM_HEADERS`](#MP_UNITS_BUILD_AS_SYSTEM_HEADERS){ #MP_UNITS_BUILD_AS_SYSTEM_HEADERS }
|
||||
|
||||
[conan build all support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
: [:octicons-tag-24: 2.2.0][cmake as system headers support] · :octicons-milestone-24: `ON`/`OFF` (Default: `OFF`)
|
||||
|
||||
[`user.mp-units.build:skip_la`](#user-skip-la){ #user-skip-la }
|
||||
Exports library as system headers.
|
||||
|
||||
: [:octicons-tag-24: 2.2.0][conan skip la support] · :octicons-milestone-24: `True`/`False` (Default: `True`)
|
||||
[cmake as system headers support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
If `user.mp-units.build:all` is enabled, among others, Conan installs the external
|
||||
[wg21-linear_algebra](https://conan.io/center/recipes/wg21-linear_algebra)
|
||||
dependency and enables the compilation of linear algebra-based tests and usage examples.
|
||||
Such behavior can be disabled with this option.
|
||||
[`MP_UNITS_BUILD_CXX_MODULES`](#MP_UNITS_BUILD_CXX_MODULES){ #MP_UNITS_BUILD_CXX_MODULES }
|
||||
|
||||
[conan skip la support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
: [:octicons-tag-24: 2.2.0][cmake build cxx modules support] · :octicons-milestone-24: `ON`/`OFF` (Default: `OFF`)
|
||||
|
||||
[`user.mp-units.analyze:clang-tidy`](#user.mp-units.analyze-clang-tidy){ #user.mp-units.analyze-clang-tidy }
|
||||
Adds C++ modules to the list of default targets.
|
||||
|
||||
: [:octicons-tag-24: 2.2.0][conan clang-tidy support] · :octicons-milestone-24: `True`/`False` (Default: `False`)
|
||||
[cmake build cxx modules support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
Enables clang-tidy analysis.
|
||||
[`MP_UNITS_BUILD_IMPORT_STD`](#MP_UNITS_BUILD_IMPORT_STD){ #MP_UNITS_BUILD_IMPORT_STD }
|
||||
|
||||
[conan clang-tidy support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
: [:octicons-tag-24: 2.3.0][cmake import std support] · :octicons-milestone-24: `ON`/`OFF` (Default: `OFF`)
|
||||
|
||||
### CMake options
|
||||
Enables `import std;` usage.
|
||||
|
||||
[`MP_UNITS_BUILD_AS_SYSTEM_HEADERS`](#MP_UNITS_BUILD_AS_SYSTEM_HEADERS){ #MP_UNITS_BUILD_AS_SYSTEM_HEADERS }
|
||||
[cmake import std support]: https://github.com/mpusz/mp-units/releases/tag/v2.3.0
|
||||
|
||||
: [:octicons-tag-24: 2.2.0][cmake as system headers support] · :octicons-milestone-24: `ON`/`OFF` (Default: `OFF`)
|
||||
[`MP_UNITS_API_STD_FORMAT`](#MP_UNITS_API_STD_FORMAT){ #MP_UNITS_API_STD_FORMAT }
|
||||
|
||||
Exports library as system headers.
|
||||
: [:octicons-tag-24: 2.2.0][cmake std::format support] · :octicons-milestone-24: `ON`/`OFF` (Default: automatically determined)
|
||||
|
||||
[cmake as system headers support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
Enables the usage of [`std::format`](https://en.cppreference.com/w/cpp/utility/format/format)
|
||||
and associated facilities for text formatting. If it is not supported, then
|
||||
the [{fmt}](https://github.com/fmtlib/fmt) library is used instead.
|
||||
|
||||
[`MP_UNITS_BUILD_CXX_MODULES`](#MP_UNITS_BUILD_CXX_MODULES){ #MP_UNITS_BUILD_CXX_MODULES }
|
||||
[cmake std::format support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
: [:octicons-tag-24: 2.2.0][cmake build cxx modules support] · :octicons-milestone-24: `ON`/`OFF` (Default: `OFF`)
|
||||
[`MP_UNITS_API_STRING_VIEW_RET`](#MP_UNITS_API_STRING_VIEW_RET){ #MP_UNITS_API_STRING_VIEW_RET }
|
||||
|
||||
Adds C++ modules to the list of default targets.
|
||||
: [:octicons-tag-24: 2.2.0][cmake returning string_view] · :octicons-milestone-24: `ON`/`OFF` (Default: automatically determined)
|
||||
|
||||
[cmake build cxx modules support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
Enables returning `std::string_view` from the
|
||||
[`unit_symbol()`](../users_guide/framework_basics/text_output.md#unit_symbol)
|
||||
and [`dimension_symbol()`](../users_guide/framework_basics/text_output.md#dimension_symbol)
|
||||
functions. If this feature is not available, those functions will return
|
||||
`mp_units::basic_fixed_string<CharT, N>` instead.
|
||||
|
||||
[`MP_UNITS_BUILD_IMPORT_STD`](#MP_UNITS_BUILD_IMPORT_STD){ #MP_UNITS_BUILD_IMPORT_STD }
|
||||
[cmake returning string_view]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
: [:octicons-tag-24: 2.3.0][cmake import std support] · :octicons-milestone-24: `ON`/`OFF` (Default: `OFF`)
|
||||
[`MP_UNITS_API_NO_CRTP`](#MP_UNITS_API_NO_CRTP){ #MP_UNITS_API_NO_CRTP }
|
||||
|
||||
Enables `import std;` usage.
|
||||
: [:octicons-tag-24: 2.2.0][cmake no crtp support] · :octicons-milestone-24: `ON`/`OFF` (Default: automatically determined)
|
||||
|
||||
[cmake import std support]: https://github.com/mpusz/mp-units/releases/tag/v2.3.0
|
||||
Removes the need for the usage of the CRTP idiom in the
|
||||
[`quantity_spec` definitions](../users_guide/framework_basics/systems_of_quantities.md#defining-quantities).
|
||||
|
||||
[`MP_UNITS_API_STD_FORMAT`](#MP_UNITS_API_STD_FORMAT){ #MP_UNITS_API_STD_FORMAT }
|
||||
[cmake no crtp support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
: [:octicons-tag-24: 2.2.0][cmake std::format support] · :octicons-milestone-24: `ON`/`OFF` (Default: automatically determined)
|
||||
[`MP_UNITS_API_CONTRACTS`](#MP_UNITS_API_CONTRACTS){ #MP_UNITS_API_CONTRACTS }
|
||||
|
||||
Enables the usage of [`std::format`](https://en.cppreference.com/w/cpp/utility/format/format)
|
||||
and associated facilities for text formatting. If it is not supported, then
|
||||
the [{fmt}](https://github.com/fmtlib/fmt) library is used instead.
|
||||
: [:octicons-tag-24: 2.2.0][cmake contracts] · :octicons-milestone-24: `NONE`/`GSL-LITE`/`MS-GSL` (Default: `GSL-LITE`)
|
||||
|
||||
[cmake std::format support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
Enables checking of preconditions and additional asserts in the code.
|
||||
|
||||
[`MP_UNITS_API_STRING_VIEW_RET`](#MP_UNITS_API_STRING_VIEW_RET){ #MP_UNITS_API_STRING_VIEW_RET }
|
||||
[cmake contracts]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
: [:octicons-tag-24: 2.2.0][cmake returning string_view] · :octicons-milestone-24: `ON`/`OFF` (Default: automatically determined)
|
||||
[`MP_UNITS_API_FREESTANDING`](#MP_UNITS_API_FREESTANDING){ #MP_UNITS_API_FREESTANDING }
|
||||
|
||||
Enables returning `std::string_view` from the
|
||||
[`unit_symbol()`](../users_guide/framework_basics/text_output.md#unit_symbol)
|
||||
and [`dimension_symbol()`](../users_guide/framework_basics/text_output.md#dimension_symbol)
|
||||
functions. If this feature is not available, those functions will return
|
||||
`mp_units::basic_fixed_string<CharT, N>` instead.
|
||||
: [:octicons-tag-24: 2.2.0][cmake freestanding] · :octicons-milestone-24: `ON`/`OFF` (Default: `OFF`)
|
||||
|
||||
[cmake returning string_view]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
Configures the library in the [freestanding](https://en.cppreference.com/w/cpp/freestanding)
|
||||
mode. When enabled, the library's source code should build with the compiler's
|
||||
[`-ffreestanding`](https://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html) compilation option
|
||||
without any issues.
|
||||
|
||||
[`MP_UNITS_API_NO_CRTP`](#MP_UNITS_API_NO_CRTP){ #MP_UNITS_API_NO_CRTP }
|
||||
|
||||
: [:octicons-tag-24: 2.2.0][cmake no crtp support] · :octicons-milestone-24: `ON`/`OFF` (Default: automatically determined)
|
||||
|
||||
Removes the need for the usage of the CRTP idiom in the
|
||||
[`quantity_spec` definitions](../users_guide/framework_basics/systems_of_quantities.md#defining-quantities).
|
||||
|
||||
[cmake no crtp support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
[`MP_UNITS_API_CONTRACTS`](#MP_UNITS_API_CONTRACTS){ #MP_UNITS_API_CONTRACTS }
|
||||
|
||||
: [:octicons-tag-24: 2.2.0][cmake contracts] · :octicons-milestone-24: `NONE`/`GSL-LITE`/`MS-GSL` (Default: `GSL-LITE`)
|
||||
|
||||
Enables checking of preconditions and additional asserts in the code.
|
||||
|
||||
[cmake contracts]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
[`MP_UNITS_API_FREESTANDING`](#MP_UNITS_API_FREESTANDING){ #MP_UNITS_API_FREESTANDING }
|
||||
|
||||
: [:octicons-tag-24: 2.2.0][cmake freestanding] · :octicons-milestone-24: `ON`/`OFF` (Default: `OFF`)
|
||||
|
||||
Configures the library in the [freestanding](https://en.cppreference.com/w/cpp/freestanding)
|
||||
mode. When enabled, the library's source code should build with the compiler's
|
||||
[`-ffreestanding`](https://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html) compilation option
|
||||
without any issues.
|
||||
|
||||
[cmake freestanding]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
#### Options for mp-units project developers
|
||||
|
||||
[`MP_UNITS_DEV_BUILD_LA`](#MP_UNITS_DEV_BUILD_LA){ #MP_UNITS_DEV_BUILD_LA }
|
||||
|
||||
: [:octicons-tag-24: 2.2.0][cmake build la support] · :octicons-milestone-24: `ON`/`OFF` (Default: `ON`)
|
||||
|
||||
Enables building code depending on the linear algebra library.
|
||||
|
||||
[cmake build la support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
[`MP_UNITS_DEV_IWYU`](#MP_UNITS_DEV_IWYU){ #MP_UNITS_DEV_IWYU }
|
||||
|
||||
: [:octicons-tag-24: 2.2.0][cmake iwyu support] · :octicons-milestone-24: `ON`/`OFF` (Default: `OFF`)
|
||||
|
||||
Enables include-what-you-use analysis.
|
||||
|
||||
[cmake iwyu support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
[`MP_UNITS_DEV_CLANG_TIDY`](#MP_UNITS_DEV_CLANG_TIDY){ #MP_UNITS_DEV_CLANG_TIDY }
|
||||
|
||||
: [:octicons-tag-24: 2.2.0][cmake clang-tidy support] · :octicons-milestone-24: `ON`/`OFF` (Default: `OFF`)
|
||||
|
||||
Enables clang-tidy analysis.
|
||||
|
||||
[cmake clang-tidy support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.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
|
||||
```
|
||||
|
||||
!!! tip
|
||||
|
||||
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.
|
||||
[cmake freestanding]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
|
||||
## Installation and reuse
|
||||
@@ -461,42 +255,12 @@ only a few of many options possible.
|
||||
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
|
||||
If you are new to the Conan package manager you may want to read
|
||||
[Obtaining Dependencies](#obtaining-dependencies) and refer to the
|
||||
[Consuming packages](https://docs.conan.io/2/tutorial/consuming_packages.html)
|
||||
chapter of the official Conan documentation for more information.
|
||||
|
||||
@@ -512,7 +276,6 @@ The following steps may be performed to obtain an official library release:
|
||||
mp-units/2.2.0
|
||||
|
||||
[options]
|
||||
mp-units:cxx_modules=True
|
||||
|
||||
[layout]
|
||||
cmake_layout
|
||||
@@ -522,8 +285,7 @@ The following steps may be performed to obtain an official library release:
|
||||
CMakeDeps
|
||||
```
|
||||
|
||||
2. Import **mp-units** and its dependencies definitions to your project's build procedure
|
||||
with `find_package`:
|
||||
2. Import **mp-units** and its dependencies definitions with `find_package`:
|
||||
|
||||
```cmake
|
||||
find_package(mp-units REQUIRED)
|
||||
@@ -552,7 +314,7 @@ of **mp-units** all the time.
|
||||
|
||||
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
|
||||
(CI and C++ build environments are 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.
|
||||
|
||||
@@ -572,7 +334,6 @@ with the following differences:
|
||||
mp-units/2.3.0@mpusz/testing
|
||||
|
||||
[options]
|
||||
mp-units:cxx_modules=True
|
||||
|
||||
[layout]
|
||||
cmake_layout
|
||||
@@ -594,91 +355,60 @@ with the following differences:
|
||||
conan install . -pr <your_conan_profile> -s compiler.cppstd=20 -b=missing -u
|
||||
```
|
||||
|
||||
??? info "Alternative installation scenarios"
|
||||
|
||||
### Install
|
||||
### Copy
|
||||
|
||||
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:
|
||||
As **mp-units** is a C++ header-only library you can simply copy all needed _src/*/include_ subdirectories
|
||||
to your source tree.
|
||||
|
||||
```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
|
||||
```
|
||||
!!! 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.
|
||||
|
||||
|
||||
## Contributing (or just building all the tests and examples)
|
||||
### Copy + CMake
|
||||
|
||||
In case you would like to build all the **mp-units** source code (with unit tests and examples),
|
||||
you should:
|
||||
If you copy the **mp-units** library source code from **the project's _./src_ directory**
|
||||
(not the entire repo from its root), you can reuse CMake targets defined by the library.
|
||||
To do so, **you should use _CMakeLists.txt_ file from the _./src_ directory**:
|
||||
|
||||
1. Use the _CMakeLists.txt_ from the top-level directory.
|
||||
2. Run Conan with [`user.mp-units.build:all`](#user.mp-units.build-all) = `True`.
|
||||
|
||||
```shell
|
||||
git clone https://github.com/mpusz/mp-units.git && cd units
|
||||
conan build . -pr <your_conan_profile> -s compiler.cppstd=23 -o '&:cxx_modules=True' -c user.mp-units.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 all_verify_interface_header_sets
|
||||
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 mkdocs-rss-plugin
|
||||
```
|
||||
|
||||
Additionally, a [Cairo Graphics library](https://www.cairographics.org/) is required by
|
||||
Material for MkDocs. Please follow the
|
||||
[official MkDocs documentation to install it](https://squidfunk.github.io/mkdocs-material/plugins/requirements/image-processing/#cairo-graphics).
|
||||
|
||||
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
|
||||
```cmake
|
||||
add_subdirectory(<path_to_mp_units_lib_folder>)
|
||||
# ...
|
||||
target_link_libraries(<your_target> <PUBLIC|PRIVATE|INTERFACE> mp-units::mp-units)
|
||||
```
|
||||
|
||||
- [build the documentation](https://squidfunk.github.io/mkdocs-material/creating-your-site/#building-your-site)
|
||||
!!! 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.
|
||||
|
||||
!!! important "Important: Library users should not use the top-level CMake file"
|
||||
|
||||
Top level _CMakeLists.txt_ file should only be used by **mp-units developers and contributors**
|
||||
as an entry point for the project's development.
|
||||
_./src/CMakeLists.txt_ contains only a pure library definition and **should be used by the
|
||||
customers** that prefer to use CMake's
|
||||
[`add_subdirectory()`](https://cmake.org/cmake/help/latest/command/add_subdirectory.html) to
|
||||
handle the dependencies.
|
||||
|
||||
To learn more about the rationale, please check our
|
||||
[FAQ](faq.md#why-dont-we-have-cmake-options-to-disable-the-building-of-tests-and-examples).
|
||||
|
||||
|
||||
### Install
|
||||
|
||||
If 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
|
||||
mkdocs build
|
||||
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
|
||||
```
|
||||
|
||||
|
||||
## Packaging
|
||||
|
||||
To test CMake installation and Conan packaging or create a Conan package run:
|
||||
|
||||
```shell
|
||||
conan create . --user <username> --channel <channel> -pr <your_conan_profile> -s compiler.cppstd=20 -o '&:cxx_modules=True' -c user.mp-units.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.2.0@<user>/<channel>
|
||||
```
|
||||
|
150
docs/getting_started/project_structure.md
Normal file
150
docs/getting_started/project_structure.md
Normal file
@@ -0,0 +1,150 @@
|
||||
# Project structure
|
||||
|
||||
This chapter provides a high level overview of the project to make it easier to navigate, build,
|
||||
and use.
|
||||
|
||||
|
||||
## CMake projects and dependencies
|
||||
|
||||
The [GitHub repository](https://github.com/mpusz/mp-units) contains three independent CMake-based
|
||||
projects:
|
||||
|
||||
- **_./src_**
|
||||
|
||||
- header-only project containing whole **mp-units** library
|
||||
- _./src/CMakeLists.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) or [ms-gsl](https://github.com/microsoft/GSL)
|
||||
to verify runtime contracts (if contract checking is enabled),
|
||||
- [{fmt}](https://github.com/fmtlib/fmt) to provide text formatting of quantities
|
||||
(if `std::format` is not supported yet on a specific compiler).
|
||||
|
||||
- **_._**
|
||||
|
||||
- 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.
|
||||
|
||||
- **_./test_package_**
|
||||
|
||||
- CMake library installation and Conan package verification.
|
||||
|
||||
|
||||
!!! important "Important: Library users should not use the top-level CMake file"
|
||||
|
||||
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()`](https://cmake.org/cmake/help/latest/command/add_subdirectory.html) to
|
||||
handle the dependencies.
|
||||
|
||||
To learn more about the rationale, please check our
|
||||
[FAQ](faq.md#why-dont-we-have-cmake-options-to-disable-the-building-of-tests-and-examples).
|
||||
|
||||
## Modules
|
||||
|
||||
The **mp-units** library provides the following C++ modules:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
mp_units --- mp_units.systems --- mp_units.core
|
||||
```
|
||||
|
||||
| C++ Module | CMake Target | Contents |
|
||||
|--------------------|----------------------|----------------------------------------------------------|
|
||||
| `mp_units.core` | `mp-units::core` | Core library framework and systems-independent utilities |
|
||||
| `mp_units.systems` | `mp-units::systems` | All the systems of quantities and units |
|
||||
| `mp_units` | `mp-units::mp-units` | Core + Systems |
|
||||
|
||||
!!! note
|
||||
|
||||
C++ modules are provided within the package only when:
|
||||
|
||||
- [`cxx_modules`](installation_and_usage.md#cxx_modules) Conan option is set to `True`,
|
||||
- [`MP_UNITS_BUILD_CXX_MODULES`](installation_and_usage.md#MP_UNITS_BUILD_CXX_MODULES) CMake option is set to `ON`.
|
||||
|
||||
## Header files
|
||||
|
||||
All of the project's header files can be found in the `mp-units/...` subdirectory.
|
||||
|
||||
### Core library
|
||||
|
||||
- `mp-units/framework.h` contains the entire library's framework definitions,
|
||||
- `mp-units/concepts.h` exposes only the library's concepts for generic code needs,
|
||||
- `mp-units/format.h` provides text formatting support,
|
||||
- `mp-units/ostream.h` enables streaming of the library's objects to the text output,
|
||||
- `mp-units/math.h` provides overloads of common math functions for quantities,
|
||||
- `mp-units/random.h` provides C++ pseudo-random number generators for quantities,
|
||||
- `mp-units/compat_macros.h` provides macros for [wide compatibility](../users_guide/use_cases/wide_compatibility.md).
|
||||
|
||||
??? info "More details"
|
||||
|
||||
More detailed header files can be found in subfolders which typically should not be
|
||||
included by the end users:
|
||||
|
||||
- `mp-units/framework/...` provides all the public interfaces of the framework,
|
||||
- `mp-units/bits/...` provides private implementation details only (no public definitions),
|
||||
- `mp-units/ext/...` contains external dependencies that at some point in the future should
|
||||
be replaced with C++ standard library facilities.
|
||||
|
||||
### Systems and associated utilities
|
||||
|
||||
The systems definitions can be found in the `mp-units/systems/...` subdirectory:
|
||||
|
||||
#### Systems of quantities
|
||||
|
||||
- `mp-units/systems/isq.h` provides
|
||||
[International System of Quantities (ISQ)](https://en.wikipedia.org/wiki/International_System_of_Quantities)
|
||||
definitions,
|
||||
|
||||
??? tip "Tip: Improving compile times"
|
||||
|
||||
`mp-units/systems/isq.h` might be expensive to compile in every translation unit. There are
|
||||
some smaller, domain targeted files available for explicit inclusion in the
|
||||
`mp-units/systems/isq/...` subdirectory.
|
||||
|
||||
#### Systems of units
|
||||
|
||||
- `mp-units/systems/si.h` provides
|
||||
[International System of Units (SI)](https://en.wikipedia.org/wiki/International_System_of_Units)
|
||||
definitions and associated math functions,
|
||||
- `mp-units/systems/angular.h` provides strong angular units and associated math functions,
|
||||
- `mp-units/systems/international.h` provides
|
||||
[international yard and pound](https://en.wikipedia.org/wiki/International_yard_and_pound) units,
|
||||
- `mp-units/systems/imperial.h` includes `international.h` and extends it with
|
||||
[imperial units](https://en.wikipedia.org/wiki/Imperial_units),
|
||||
- `mp-units/systems/usc.h` includes `international.h` and extends it with
|
||||
[United States customary system of units](https://en.wikipedia.org/wiki/United_States_customary_units),
|
||||
- `mp-units/systems/cgs.h` provides
|
||||
[centimetre-gram-second system of units](https://en.wikipedia.org/wiki/Centimetre%E2%80%93gram%E2%80%93second_system_of_units),
|
||||
- `mp-units/systems/iau.h` provides
|
||||
[astronomical system of units](https://en.wikipedia.org/wiki/Astronomical_system_of_units),
|
||||
- `mp-units/systems/hep.h` provides units used in
|
||||
[high-energy physics](https://en.wikipedia.org/wiki/Particle_physics),
|
||||
- `mp-units/systems/typographic.h` provides units used in
|
||||
[typography or typesetting](https://en.wikipedia.org/wiki/Typographic_unit),
|
||||
- `mp-units/systems/natural.h` provides an example implementation of
|
||||
[natural units](https://en.wikipedia.org/wiki/Natural_units).
|
||||
|
||||
??? tip "Tip: Improving compile times"
|
||||
|
||||
`mp-units/systems/si.h` might be expensive to compile in every translation unit.
|
||||
There are some smaller files available for explicit inclusion in the
|
||||
`mp-units/systems/si/...` subdirectory.
|
||||
|
||||
`mp-units/systems/si/unit_symbols.h` is the most expensive to include.
|
9
docs/javascripts/iframeResizer.contentWindow.min.js
vendored
Normal file
9
docs/javascripts/iframeResizer.contentWindow.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
8
docs/javascripts/iframeResizer.min.js
vendored
Normal file
8
docs/javascripts/iframeResizer.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
docs/javascripts/jquery.min.js
vendored
Normal file
2
docs/javascripts/jquery.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -179,7 +179,7 @@ For example, here is how it can be done for the [P1385](https://wg21.link/p1385)
|
||||
using la_vector = STD_LA::fixed_size_column_vector<double, 3>;
|
||||
|
||||
template<>
|
||||
inline constexpr bool mp_units::is_vector<la_vector> = true;
|
||||
constexpr bool mp_units::is_vector<la_vector> = true;
|
||||
```
|
||||
|
||||
With the above, we can use `la_vector` as a representation type for our quantity:
|
||||
@@ -233,7 +233,7 @@ For example, we can do the following:
|
||||
```cpp
|
||||
template<class T>
|
||||
requires mp_units::is_scalar<T>
|
||||
inline constexpr bool mp_units::is_vector<T> = true;
|
||||
constexpr bool mp_units::is_vector<T> = true;
|
||||
```
|
||||
|
||||
which says that every type that can be used as a scalar representation is also allowed for vector
|
||||
|
@@ -180,7 +180,7 @@ with `true` for one or more of the following variable templates:
|
||||
```cpp
|
||||
template<class T>
|
||||
requires mp_units::is_scalar<T>
|
||||
inline constexpr bool mp_units::is_vector<T> = true;
|
||||
constexpr bool mp_units::is_vector<T> = true;
|
||||
```
|
||||
|
||||
|
||||
|
@@ -232,7 +232,7 @@ A unit can be defined by the user in one of the following ways:
|
||||
|
||||
```cpp
|
||||
template<PrefixableUnit U> struct kilo_ : prefixed_unit<"k", mag_power<10, 3>, U{}> {};
|
||||
template<PrefixableUnit auto U> inline constexpr kilo_<decltype(U)> kilo;
|
||||
template<PrefixableUnit auto U> constexpr kilo_<decltype(U)> kilo;
|
||||
|
||||
inline constexpr struct second final : named_unit<"s", kind_of<isq::time>> {} second;
|
||||
inline constexpr struct minute final : named_unit<"min", mag<60> * second> {} minute;
|
||||
|
@@ -138,7 +138,7 @@ Each prefix is implemented similarly to the following:
|
||||
|
||||
```cpp
|
||||
template<PrefixableUnit U> struct quecto_ : prefixed_unit<"q", mag_power<10, -30>, U{}> {};
|
||||
template<PrefixableUnit auto U> inline constexpr quecto_<decltype(U)> quecto;
|
||||
template<PrefixableUnit auto U> constexpr quecto_<decltype(U)> quecto;
|
||||
```
|
||||
|
||||
and then a [PrefixableUnit](concepts.md#PrefixableUnit) can be prefixed in the following
|
||||
@@ -154,7 +154,7 @@ IT industry can be implemented as:
|
||||
|
||||
```cpp
|
||||
template<PrefixableUnit U> struct yobi_ : prefixed_unit<"Yi", mag_power<2, 80>, U{}> {};
|
||||
template<PrefixableUnit auto U> inline constexpr yobi_<decltype(U)> yobi;
|
||||
template<PrefixableUnit auto U> constexpr yobi_<decltype(U)> yobi;
|
||||
```
|
||||
|
||||
## Scaled units
|
||||
|
@@ -288,7 +288,7 @@ specialization for a specific unit:
|
||||
|
||||
```cpp
|
||||
template<>
|
||||
inline constexpr bool space_before_unit_symbol<non_si::degree> = false;
|
||||
constexpr bool space_before_unit_symbol<non_si::degree> = false;
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
@@ -42,7 +42,7 @@ import mp_units.core;
|
||||
|
||||
template<std::movable T, MP_UNITS_CONSTRAINED_NTTP_WORKAROUND(std::convertible_to<T>) auto Min,
|
||||
MP_UNITS_CONSTRAINED_NTTP_WORKAROUND(std::convertible_to<T>) auto Max>
|
||||
inline constexpr auto is_in_range = [](const auto& v) { return std::clamp(v, T{Min}, T{Max}) == v; };
|
||||
MP_UNITS_INLINE constexpr auto is_in_range = [](const auto& v) { return std::clamp(v, T{Min}, T{Max}) == v; };
|
||||
|
||||
template<std::movable T, MP_UNITS_CONSTRAINED_NTTP_WORKAROUND(std::convertible_to<T>) auto Min,
|
||||
MP_UNITS_CONSTRAINED_NTTP_WORKAROUND(std::convertible_to<T>) auto Max>
|
||||
@@ -63,10 +63,10 @@ public:
|
||||
};
|
||||
|
||||
template<typename T, auto Min, auto Max>
|
||||
inline constexpr bool mp_units::is_scalar<ranged_representation<T, Min, Max>> = mp_units::is_scalar<T>;
|
||||
constexpr bool mp_units::is_scalar<ranged_representation<T, Min, Max>> = mp_units::is_scalar<T>;
|
||||
|
||||
template<typename T, auto Min, auto Max>
|
||||
inline constexpr bool mp_units::treat_as_floating_point<ranged_representation<T, Min, Max>> =
|
||||
constexpr bool mp_units::treat_as_floating_point<ranged_representation<T, Min, Max>> =
|
||||
mp_units::treat_as_floating_point<T>;
|
||||
|
||||
template<typename T, auto Min, auto Max, typename Char>
|
||||
|
@@ -114,11 +114,10 @@ public:
|
||||
};
|
||||
|
||||
template<typename T, typename Validator>
|
||||
inline constexpr bool mp_units::is_scalar<validated_type<T, Validator>> = mp_units::is_scalar<T>;
|
||||
constexpr bool mp_units::is_scalar<validated_type<T, Validator>> = mp_units::is_scalar<T>;
|
||||
|
||||
template<typename T, typename Validator>
|
||||
inline constexpr bool mp_units::treat_as_floating_point<validated_type<T, Validator>> =
|
||||
mp_units::treat_as_floating_point<T>;
|
||||
constexpr bool mp_units::treat_as_floating_point<validated_type<T, Validator>> = mp_units::treat_as_floating_point<T>;
|
||||
|
||||
|
||||
template<typename CharT, typename Traits, typename T, typename Validator>
|
||||
|
@@ -47,13 +47,13 @@ namespace kalman {
|
||||
namespace detail {
|
||||
|
||||
template<mp_units::Dimension auto... Ds>
|
||||
inline constexpr bool are_time_derivatives = false;
|
||||
constexpr bool are_time_derivatives = false;
|
||||
|
||||
template<mp_units::Dimension auto D>
|
||||
inline constexpr bool are_time_derivatives<D> = true;
|
||||
constexpr bool are_time_derivatives<D> = true;
|
||||
|
||||
template<mp_units::Dimension auto D1, mp_units::Dimension auto D2, mp_units::Dimension auto... Ds>
|
||||
inline constexpr bool are_time_derivatives<D1, D2, Ds...> =
|
||||
constexpr bool are_time_derivatives<D1, D2, Ds...> =
|
||||
(D1 / D2 == mp_units::isq::dim_time) && are_time_derivatives<D2, Ds...>;
|
||||
|
||||
} // namespace detail
|
||||
|
@@ -40,7 +40,7 @@ import mp_units;
|
||||
|
||||
template<class T>
|
||||
requires mp_units::is_scalar<T>
|
||||
inline constexpr bool mp_units::is_vector<T> = true;
|
||||
constexpr bool mp_units::is_vector<T> = true;
|
||||
|
||||
using namespace mp_units;
|
||||
|
||||
|
@@ -40,7 +40,7 @@ import mp_units;
|
||||
|
||||
template<class T>
|
||||
requires mp_units::is_scalar<T>
|
||||
inline constexpr bool mp_units::is_vector<T> = true;
|
||||
constexpr bool mp_units::is_vector<T> = true;
|
||||
|
||||
using namespace mp_units;
|
||||
|
||||
|
@@ -40,7 +40,7 @@ import mp_units;
|
||||
|
||||
template<class T>
|
||||
requires mp_units::is_scalar<T>
|
||||
inline constexpr bool mp_units::is_vector<T> = true;
|
||||
constexpr bool mp_units::is_vector<T> = true;
|
||||
|
||||
using namespace mp_units;
|
||||
|
||||
|
@@ -132,12 +132,12 @@ private:
|
||||
} // namespace
|
||||
|
||||
template<class T>
|
||||
inline constexpr bool mp_units::treat_as_floating_point<measurement<T>> = mp_units::treat_as_floating_point<T>;
|
||||
constexpr bool mp_units::treat_as_floating_point<measurement<T>> = mp_units::treat_as_floating_point<T>;
|
||||
|
||||
template<class T>
|
||||
inline constexpr bool mp_units::is_scalar<measurement<T>> = true;
|
||||
constexpr bool mp_units::is_scalar<measurement<T>> = true;
|
||||
template<class T>
|
||||
inline constexpr bool mp_units::is_vector<measurement<T>> = true;
|
||||
constexpr bool mp_units::is_vector<measurement<T>> = true;
|
||||
|
||||
static_assert(mp_units::RepresentationOf<measurement<double>, mp_units::quantity_character::scalar>);
|
||||
|
||||
|
@@ -41,7 +41,7 @@ import mp_units;
|
||||
|
||||
template<class T>
|
||||
requires mp_units::is_scalar<T>
|
||||
inline constexpr bool mp_units::is_vector<T> = true;
|
||||
constexpr bool mp_units::is_vector<T> = true;
|
||||
|
||||
int main()
|
||||
{
|
||||
|
@@ -44,7 +44,7 @@ import mp_units;
|
||||
// types instead of requiring the usage of Linear Algebra library for this simple example
|
||||
template<class T>
|
||||
requires mp_units::is_scalar<T>
|
||||
inline constexpr bool mp_units::is_vector<T> = true;
|
||||
constexpr bool mp_units::is_vector<T> = true;
|
||||
|
||||
namespace {
|
||||
|
||||
|
@@ -35,7 +35,7 @@ import mp_units;
|
||||
|
||||
template<class T>
|
||||
requires mp_units::is_scalar<T>
|
||||
inline constexpr bool mp_units::is_vector<T> = true;
|
||||
constexpr bool mp_units::is_vector<T> = true;
|
||||
|
||||
int main()
|
||||
{
|
||||
|
@@ -39,7 +39,7 @@ import mp_units;
|
||||
|
||||
template<class T>
|
||||
requires mp_units::is_scalar<T>
|
||||
inline constexpr bool mp_units::is_vector<T> = true;
|
||||
constexpr bool mp_units::is_vector<T> = true;
|
||||
|
||||
namespace {
|
||||
|
||||
|
@@ -53,7 +53,7 @@ struct height_above_ellipsoid_t final : absolute_point_origin<isq::altitude> {
|
||||
static constexpr earth_gravity_model egm = M;
|
||||
};
|
||||
template<earth_gravity_model M>
|
||||
inline constexpr height_above_ellipsoid_t<M> height_above_ellipsoid; // NOLINT(google-readability-casting)
|
||||
constexpr height_above_ellipsoid_t<M> height_above_ellipsoid; // NOLINT(google-readability-casting)
|
||||
|
||||
template<earth_gravity_model M>
|
||||
using hae_altitude = quantity_point<isq::altitude[si::metre], height_above_ellipsoid<M>>;
|
||||
|
@@ -64,6 +64,9 @@ theme:
|
||||
# Plugins
|
||||
plugins:
|
||||
- blog
|
||||
- exclude:
|
||||
glob:
|
||||
- api_reference/src/*
|
||||
- rss:
|
||||
match_path: blog/posts/.*
|
||||
date_from_meta:
|
||||
@@ -130,8 +133,10 @@ nav:
|
||||
- Introduction: getting_started/introduction.md
|
||||
- Quick Start: getting_started/quick_start.md
|
||||
- Look and Feel: getting_started/look_and_feel.md
|
||||
- Project Structure: getting_started/project_structure.md
|
||||
- C++ compiler support (API/ABI): getting_started/cpp_compiler_support.md
|
||||
- Installation and Usage: getting_started/installation_and_usage.md
|
||||
- Contributing: getting_started/contributing.md
|
||||
- FAQ: getting_started/faq.md
|
||||
- User's Guide:
|
||||
- Terms and Definitions: users_guide/terms_and_definitions.md
|
||||
@@ -173,6 +178,7 @@ nav:
|
||||
- Appendix:
|
||||
- Glossary: appendix/glossary.md
|
||||
- References: appendix/references.md
|
||||
- API Reference: api_reference.md
|
||||
- Blog:
|
||||
- blog/index.md
|
||||
- Release Notes: release_notes.md
|
||||
|
@@ -4,4 +4,5 @@ identify
|
||||
mkdocs-material
|
||||
mkdocs-rss-plugin
|
||||
mkdocs-material[imaging]
|
||||
mkdocs-exclude
|
||||
mike
|
||||
|
@@ -122,7 +122,7 @@ public:
|
||||
MP_UNITS_EXPORT_END
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_integer =
|
||||
constexpr bool is_integer =
|
||||
std::is_integral_v<T> && !std::is_same_v<T, bool> && !std::is_same_v<T, char> && !std::is_same_v<T, wchar_t>;
|
||||
|
||||
// Converts a character to ASCII. Returns a number > 127 on conversion failure.
|
||||
|
@@ -76,6 +76,10 @@
|
||||
#if !defined MP_UNITS_HOSTED && defined __STDC_HOSTED__
|
||||
#define MP_UNITS_HOSTED __STDC_HOSTED__
|
||||
#endif
|
||||
|
||||
// workarounds for https://cplusplus.github.io/CWG/issues/2387.html
|
||||
#define MP_UNITS_INLINE inline
|
||||
|
||||
#if MP_UNITS_COMP_GCC
|
||||
|
||||
#define MP_UNITS_REMOVE_CONST(expr) std::remove_const_t<expr>
|
||||
|
@@ -42,36 +42,26 @@ using has_common_type = typename has_common_type_impl<void, Ts...>::type;
|
||||
template<typename... Ts>
|
||||
constexpr bool has_common_type_v = has_common_type_impl<void, Ts...>::value;
|
||||
|
||||
template<typename T, typename Other>
|
||||
struct get_common_type : std::common_type<T, Other> {};
|
||||
|
||||
template<typename T, typename Other>
|
||||
using maybe_common_type =
|
||||
std::conditional_t<has_common_type_v<T, Other>, get_common_type<T, Other>, std::type_identity<T>>::type;
|
||||
std::conditional_t<has_common_type_v<T, Other>, std::common_type<T, Other>, std::type_identity<T>>::type;
|
||||
|
||||
/**
|
||||
* @brief Details about the conversion from one quantity to another.
|
||||
* @brief Type-related details about the conversion from one quantity to another
|
||||
*
|
||||
* This struct calculates the conversion factor that needs to be applied to a number,
|
||||
* in order to convert from one quantity to another. In addition to that, it also
|
||||
* helps to determine what representations to use at which step in the conversion process,
|
||||
* This trait helps to determine what representations to use at which step in the conversion process,
|
||||
* in order to avoid overflow and underflow while not causing excessive computations.
|
||||
*
|
||||
* @note This is a low-level facility.
|
||||
*
|
||||
* @tparam To a target quantity type to cast to
|
||||
* @tparam From a source quantity type to cast from
|
||||
* @tparam M common magnitude between the two quantities
|
||||
* @tparam Rep1 first quantity representation type
|
||||
* @tparam Rep2 second quantity representation type
|
||||
*/
|
||||
template<Quantity To, Quantity From>
|
||||
requires(castable(From::quantity_spec, To::quantity_spec))
|
||||
struct magnitude_conversion_traits {
|
||||
// scale the number
|
||||
static constexpr Magnitude auto c_mag = get_canonical_unit(From::unit).mag / get_canonical_unit(To::unit).mag;
|
||||
static constexpr Magnitude auto num = numerator(c_mag);
|
||||
static constexpr Magnitude auto den = denominator(c_mag);
|
||||
static constexpr Magnitude auto irr = c_mag * (den / num);
|
||||
using c_rep_type = maybe_common_type<typename std::remove_reference_t<From>::rep, typename To::rep>;
|
||||
using c_mag_type = common_magnitude_type<c_mag>;
|
||||
template<Magnitude auto M, typename Rep1, typename Rep2>
|
||||
struct conversion_type_traits {
|
||||
using c_rep_type = maybe_common_type<Rep1, Rep2>;
|
||||
using c_mag_type = common_magnitude_type<M>;
|
||||
using multiplier_type = conditional<
|
||||
treat_as_floating_point<c_rep_type>,
|
||||
// ensure that the multiplier is also floating-point
|
||||
@@ -80,11 +70,28 @@ struct magnitude_conversion_traits {
|
||||
std::common_type_t<c_mag_type, value_type_t<c_rep_type>>, std::common_type_t<c_mag_type, double>>,
|
||||
c_mag_type>;
|
||||
using c_type = maybe_common_type<c_rep_type, multiplier_type>;
|
||||
static constexpr auto val(Magnitude auto m) { return get_value<multiplier_type>(m); };
|
||||
static constexpr multiplier_type num_mult = val(num);
|
||||
static constexpr multiplier_type den_mult = val(den);
|
||||
static constexpr multiplier_type irr_mult = val(irr);
|
||||
static constexpr multiplier_type ratio = num_mult / den_mult * irr_mult;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Value-related details about the conversion from one quantity to another
|
||||
*
|
||||
* This trait provide ingredients to calculate the conversion factor that needs to be applied
|
||||
* to a number, in order to convert from one quantity to another.
|
||||
*
|
||||
* @note This is a low-level facility.
|
||||
*
|
||||
* @tparam M common magnitude between the two quantities
|
||||
* @tparam T common multiplier representation type
|
||||
*/
|
||||
template<Magnitude auto M, typename T>
|
||||
struct conversion_value_traits {
|
||||
static constexpr Magnitude auto num = numerator(M);
|
||||
static constexpr Magnitude auto den = denominator(M);
|
||||
static constexpr Magnitude auto irr = M * (den / num);
|
||||
static constexpr T num_mult = get_value<T>(num);
|
||||
static constexpr T den_mult = get_value<T>(den);
|
||||
static constexpr T irr_mult = get_value<T>(irr);
|
||||
static constexpr T ratio = num_mult / den_mult * irr_mult;
|
||||
};
|
||||
|
||||
|
||||
@@ -96,34 +103,45 @@ struct magnitude_conversion_traits {
|
||||
*
|
||||
* @tparam To a target quantity type to cast to
|
||||
*/
|
||||
template<Quantity To, typename From>
|
||||
requires Quantity<std::remove_cvref_t<From>> &&
|
||||
(castable(std::remove_reference_t<From>::quantity_spec, To::quantity_spec)) &&
|
||||
((std::remove_reference_t<From>::unit == To::unit &&
|
||||
std::constructible_from<typename To::rep, typename std::remove_reference_t<From>::rep>) ||
|
||||
(std::remove_reference_t<From>::unit != To::unit)) // && scalable_with_<typename To::rep>))
|
||||
template<Quantity To, typename FwdFrom, Quantity From = std::remove_cvref_t<FwdFrom>>
|
||||
requires(castable(From::quantity_spec, To::quantity_spec)) &&
|
||||
((From::unit == To::unit && std::constructible_from<typename To::rep, typename From::rep>) ||
|
||||
(From::unit != To::unit)) // && scalable_with_<typename To::rep>))
|
||||
// TODO how to constrain the second part here?
|
||||
[[nodiscard]] constexpr To sudo_cast(From&& q)
|
||||
[[nodiscard]] constexpr To sudo_cast(FwdFrom&& q)
|
||||
{
|
||||
constexpr auto q_unit = std::remove_reference_t<From>::unit;
|
||||
constexpr auto q_unit = From::unit;
|
||||
if constexpr (q_unit == To::unit) {
|
||||
// no scaling of the number needed
|
||||
return {static_cast<To::rep>(std::forward<From>(q).numerical_value_is_an_implementation_detail_),
|
||||
return {static_cast<To::rep>(std::forward<FwdFrom>(q).numerical_value_is_an_implementation_detail_),
|
||||
To::reference}; // this is the only (and recommended) way to do a truncating conversion on a number, so we
|
||||
// are using static_cast to suppress all the compiler warnings on conversions
|
||||
} else {
|
||||
constexpr Magnitude auto c_mag = get_canonical_unit(From::unit).mag / get_canonical_unit(To::unit).mag;
|
||||
using type_traits = conversion_type_traits<c_mag, typename From::rep, typename To::rep>;
|
||||
using multiplier_type = typename type_traits::multiplier_type;
|
||||
// TODO the below crashed nearly every compiler I tried it on
|
||||
// auto scale = [&](std::invocable<typename type_traits::c_type> auto func) {
|
||||
auto scale = [&](auto func) {
|
||||
auto res =
|
||||
static_cast<To::rep>(func(static_cast<type_traits::c_type>(q.numerical_value_is_an_implementation_detail_)));
|
||||
return To{res, To::reference};
|
||||
};
|
||||
|
||||
// scale the number
|
||||
using traits = magnitude_conversion_traits<To, std::remove_reference_t<From>>;
|
||||
if constexpr (std::is_floating_point_v<typename traits::multiplier_type>) {
|
||||
// this results in great assembly
|
||||
auto res = static_cast<To::rep>(static_cast<traits::c_type>(q.numerical_value_is_an_implementation_detail_) *
|
||||
traits::ratio);
|
||||
return {res, To::reference};
|
||||
} else {
|
||||
// this is slower but allows conversions like 2000 m -> 2 km without loosing data
|
||||
auto res = static_cast<To::rep>(static_cast<traits::c_type>(q.numerical_value_is_an_implementation_detail_) *
|
||||
traits::num_mult / traits::den_mult * traits::irr_mult);
|
||||
return {res, To::reference};
|
||||
if constexpr (is_integral(c_mag))
|
||||
return scale([&](auto value) { return value * get_value<multiplier_type>(numerator(c_mag)); });
|
||||
else if constexpr (is_integral(pow<-1>(c_mag)))
|
||||
return scale([&](auto value) { return value / get_value<multiplier_type>(denominator(c_mag)); });
|
||||
else {
|
||||
using value_traits = conversion_value_traits<c_mag, multiplier_type>;
|
||||
if constexpr (std::is_floating_point_v<multiplier_type>)
|
||||
// this results in great assembly
|
||||
return scale([](auto value) { return value * value_traits::ratio; });
|
||||
else
|
||||
// this is slower but allows conversions like 2000 m -> 2 km without loosing data
|
||||
return scale(
|
||||
[](auto value) { return value * value_traits::num_mult / value_traits::den_mult * value_traits::irr_mult; });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -137,21 +155,18 @@ template<Quantity To, typename From>
|
||||
*
|
||||
* @tparam ToQP a target quantity point type to which to cast to
|
||||
*/
|
||||
template<QuantityPoint ToQP, typename FromQP>
|
||||
requires QuantityPoint<std::remove_cvref_t<FromQP>> &&
|
||||
(castable(std::remove_reference_t<FromQP>::quantity_spec, ToQP::quantity_spec)) &&
|
||||
(detail::same_absolute_point_origins(ToQP::point_origin, std::remove_reference_t<FromQP>::point_origin)) &&
|
||||
((std::remove_reference_t<FromQP>::unit == ToQP::unit &&
|
||||
std::constructible_from<typename ToQP::rep, typename std::remove_reference_t<FromQP>::rep>) ||
|
||||
(std::remove_reference_t<FromQP>::unit != ToQP::unit))
|
||||
[[nodiscard]] constexpr QuantityPoint auto sudo_cast(FromQP&& qp)
|
||||
template<QuantityPoint ToQP, typename FwdFromQP, QuantityPoint FromQP = std::remove_cvref_t<FwdFromQP>>
|
||||
requires(castable(FromQP::quantity_spec, ToQP::quantity_spec)) &&
|
||||
(detail::same_absolute_point_origins(ToQP::point_origin, FromQP::point_origin)) &&
|
||||
((FromQP::unit == ToQP::unit && std::constructible_from<typename ToQP::rep, typename FromQP::rep>) ||
|
||||
(FromQP::unit != ToQP::unit))
|
||||
[[nodiscard]] constexpr QuantityPoint auto sudo_cast(FwdFromQP&& qp)
|
||||
{
|
||||
using qp_type = std::remove_reference_t<FromQP>;
|
||||
if constexpr (is_same_v<std::remove_const_t<decltype(ToQP::point_origin)>,
|
||||
std::remove_const_t<decltype(qp_type::point_origin)>>) {
|
||||
std::remove_const_t<decltype(FromQP::point_origin)>>) {
|
||||
return quantity_point{
|
||||
sudo_cast<typename ToQP::quantity_type>(std::forward<FromQP>(qp).quantity_from(qp_type::point_origin)),
|
||||
qp_type::point_origin};
|
||||
sudo_cast<typename ToQP::quantity_type>(std::forward<FwdFromQP>(qp).quantity_from(FromQP::point_origin)),
|
||||
FromQP::point_origin};
|
||||
} else {
|
||||
// it's unclear how hard we should try to avoid truncation here. For now, the only corner case we cater for,
|
||||
// is when the range of the quantity type of at most one of QP or ToQP doesn't cover the offset between the
|
||||
@@ -163,23 +178,26 @@ template<QuantityPoint ToQP, typename FromQP>
|
||||
// (c) add/subtract the origin difference
|
||||
// In the following, we carefully select the order of these three operations: each of (a) and (b) is scheduled
|
||||
// either before or after (c), such that (c) acts on the largest range possible among all combination of source
|
||||
// and target unit and represenation.
|
||||
using traits = magnitude_conversion_traits<typename ToQP::quantity_type, typename qp_type::quantity_type>;
|
||||
using c_rep_type = typename traits::c_rep_type;
|
||||
if constexpr (traits::num_mult * traits::irr_mult > traits::den_mult) {
|
||||
// and target unit and representation.
|
||||
constexpr Magnitude auto c_mag = get_canonical_unit(FromQP::unit).mag / get_canonical_unit(ToQP::unit).mag;
|
||||
using type_traits = conversion_type_traits<c_mag, typename FromQP::rep, typename ToQP::rep>;
|
||||
using value_traits = conversion_value_traits<c_mag, typename type_traits::multiplier_type>;
|
||||
using c_rep_type = typename type_traits::c_rep_type;
|
||||
if constexpr (value_traits::num_mult * value_traits::irr_mult > value_traits::den_mult) {
|
||||
// original unit had a larger unit magnitude; if we first convert to the common representation but retain the
|
||||
// unit, we obtain the largest possible range while not causing truncation of fractional values. This is optimal
|
||||
// for the offset computation.
|
||||
return sudo_cast<ToQP>(
|
||||
sudo_cast<quantity_point<qp_type::reference, qp_type::point_origin, c_rep_type>>(std::forward<FromQP>(qp))
|
||||
sudo_cast<quantity_point<FromQP::reference, FromQP::point_origin, c_rep_type>>(std::forward<FwdFromQP>(qp))
|
||||
.point_for(ToQP::point_origin));
|
||||
} else {
|
||||
// new unit may have a larger unit magnitude; we first need to convert to the new unit (potentially causing
|
||||
// truncation, but no more than if we did the conversion later), but make sure we keep the larger of the two
|
||||
// representation types. Then, we can perform the offset computation.
|
||||
return sudo_cast<ToQP>(sudo_cast<quantity_point<make_reference(qp_type::quantity_spec, ToQP::unit),
|
||||
qp_type::point_origin, c_rep_type>>(std::forward<FromQP>(qp))
|
||||
.point_for(ToQP::point_origin));
|
||||
return sudo_cast<ToQP>(
|
||||
sudo_cast<quantity_point<make_reference(FromQP::quantity_spec, ToQP::unit), FromQP::point_origin, c_rep_type>>(
|
||||
std::forward<FwdFromQP>(qp))
|
||||
.point_for(ToQP::point_origin));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -40,28 +40,28 @@ namespace mp_units::detail {
|
||||
|
||||
template<std::intmax_t Value>
|
||||
requires(0 <= Value) && (Value < 10)
|
||||
inline constexpr basic_fixed_string superscript_number = u8"";
|
||||
constexpr basic_fixed_string superscript_number = u8"";
|
||||
|
||||
template<>
|
||||
inline constexpr basic_fixed_string superscript_number<0> = u8"\u2070";
|
||||
MP_UNITS_INLINE constexpr basic_fixed_string superscript_number<0> = u8"\u2070";
|
||||
template<>
|
||||
inline constexpr basic_fixed_string superscript_number<1> = u8"\u00b9";
|
||||
MP_UNITS_INLINE constexpr basic_fixed_string superscript_number<1> = u8"\u00b9";
|
||||
template<>
|
||||
inline constexpr basic_fixed_string superscript_number<2> = u8"\u00b2";
|
||||
MP_UNITS_INLINE constexpr basic_fixed_string superscript_number<2> = u8"\u00b2";
|
||||
template<>
|
||||
inline constexpr basic_fixed_string superscript_number<3> = u8"\u00b3";
|
||||
MP_UNITS_INLINE constexpr basic_fixed_string superscript_number<3> = u8"\u00b3";
|
||||
template<>
|
||||
inline constexpr basic_fixed_string superscript_number<4> = u8"\u2074";
|
||||
MP_UNITS_INLINE constexpr basic_fixed_string superscript_number<4> = u8"\u2074";
|
||||
template<>
|
||||
inline constexpr basic_fixed_string superscript_number<5> = u8"\u2075";
|
||||
MP_UNITS_INLINE constexpr basic_fixed_string superscript_number<5> = u8"\u2075";
|
||||
template<>
|
||||
inline constexpr basic_fixed_string superscript_number<6> = u8"\u2076";
|
||||
MP_UNITS_INLINE constexpr basic_fixed_string superscript_number<6> = u8"\u2076";
|
||||
template<>
|
||||
inline constexpr basic_fixed_string superscript_number<7> = u8"\u2077";
|
||||
MP_UNITS_INLINE constexpr basic_fixed_string superscript_number<7> = u8"\u2077";
|
||||
template<>
|
||||
inline constexpr basic_fixed_string superscript_number<8> = u8"\u2078";
|
||||
MP_UNITS_INLINE constexpr basic_fixed_string superscript_number<8> = u8"\u2078";
|
||||
template<>
|
||||
inline constexpr basic_fixed_string superscript_number<9> = u8"\u2079";
|
||||
MP_UNITS_INLINE constexpr basic_fixed_string superscript_number<9> = u8"\u2079";
|
||||
|
||||
inline constexpr symbol_text superscript_minus(u8"\u207b", "-");
|
||||
|
||||
|
@@ -40,10 +40,10 @@ MP_UNITS_DIAGNOSTIC_IGNORE_EXPR_ALWAYS_TF
|
||||
namespace mp_units::detail {
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_type_list = false;
|
||||
constexpr bool is_type_list = false;
|
||||
|
||||
template<template<typename...> typename T, typename... Types>
|
||||
inline constexpr bool is_type_list<T<Types...>> = true;
|
||||
constexpr bool is_type_list<T<Types...>> = true;
|
||||
|
||||
template<typename T>
|
||||
concept TypeList = is_type_list<T>;
|
||||
@@ -56,7 +56,7 @@ template<template<typename...> typename List, typename... Types>
|
||||
struct type_list_size_impl<List<Types...>> : std::integral_constant<std::size_t, sizeof...(Types)> {};
|
||||
|
||||
template<TypeList List>
|
||||
inline constexpr std::size_t type_list_size = type_list_size_impl<List>::value;
|
||||
constexpr std::size_t type_list_size = type_list_size_impl<List>::value;
|
||||
|
||||
// map
|
||||
template<typename T, template<typename...> typename To>
|
||||
|
@@ -60,26 +60,26 @@ using conditional = detail::conditional_impl<B>::template type<T, F>;
|
||||
|
||||
// is_same
|
||||
template<class T, class U>
|
||||
inline constexpr bool is_same_v = false;
|
||||
constexpr bool is_same_v = false;
|
||||
|
||||
template<class T>
|
||||
inline constexpr bool is_same_v<T, T> = true;
|
||||
constexpr bool is_same_v<T, T> = true;
|
||||
|
||||
template<class T, class U>
|
||||
using is_same = std::bool_constant<is_same_v<T, U>>;
|
||||
|
||||
// is_specialization_of
|
||||
template<typename T, template<typename...> typename Type>
|
||||
inline constexpr bool is_specialization_of = false;
|
||||
constexpr bool is_specialization_of = false;
|
||||
|
||||
template<typename... Params, template<typename...> typename Type>
|
||||
inline constexpr bool is_specialization_of<Type<Params...>, Type> = true;
|
||||
constexpr bool is_specialization_of<Type<Params...>, Type> = true;
|
||||
|
||||
template<typename T, template<auto...> typename Type>
|
||||
inline constexpr bool is_specialization_of_v = false;
|
||||
constexpr bool is_specialization_of_v = false;
|
||||
|
||||
template<auto... Params, template<auto...> typename Type>
|
||||
inline constexpr bool is_specialization_of_v<Type<Params...>, Type> = true;
|
||||
constexpr bool is_specialization_of_v<Type<Params...>, Type> = true;
|
||||
|
||||
MP_UNITS_EXPORT_END
|
||||
|
||||
@@ -92,8 +92,7 @@ void to_base_specialization_of(const volatile Type<Params...>*);
|
||||
} // namespace detail
|
||||
|
||||
template<typename T, template<typename...> typename Type>
|
||||
inline constexpr bool is_derived_from_specialization_of =
|
||||
requires(T* t) { detail::to_base_specialization_of<Type>(t); };
|
||||
constexpr bool is_derived_from_specialization_of = requires(T* t) { detail::to_base_specialization_of<Type>(t); };
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
@@ -39,34 +39,29 @@ namespace mp_units {
|
||||
|
||||
template<Reference R>
|
||||
struct delta_ {
|
||||
template<typename Rep>
|
||||
requires RepresentationOf<std::remove_cvref_t<Rep>, get_quantity_spec(R{}).character>
|
||||
[[nodiscard]] constexpr quantity<MP_UNITS_EXPRESSION_WORKAROUND(R{}), std::remove_cvref_t<Rep>> operator()(
|
||||
Rep&& lhs) const
|
||||
template<typename FwdRep, RepresentationOf<get_quantity_spec(R{}).character> Rep = std::remove_cvref_t<FwdRep>>
|
||||
[[nodiscard]] constexpr quantity<MP_UNITS_EXPRESSION_WORKAROUND(R{}), Rep> operator()(FwdRep&& lhs) const
|
||||
{
|
||||
return quantity{std::forward<Rep>(lhs), R{}};
|
||||
return quantity{std::forward<FwdRep>(lhs), R{}};
|
||||
}
|
||||
};
|
||||
|
||||
template<Reference R>
|
||||
struct absolute_ {
|
||||
template<typename Rep>
|
||||
requires RepresentationOf<std::remove_cvref_t<Rep>, get_quantity_spec(R{}).character>
|
||||
[[nodiscard]] constexpr quantity_point<MP_UNITS_EXPRESSION_WORKAROUND(R{}), default_point_origin(R{}),
|
||||
std::remove_cvref_t<Rep>>
|
||||
operator()(Rep&& lhs) const
|
||||
template<typename FwdRep, RepresentationOf<get_quantity_spec(R{}).character> Rep = std::remove_cvref_t<FwdRep>>
|
||||
[[nodiscard]] constexpr quantity_point<MP_UNITS_EXPRESSION_WORKAROUND(R{}), default_point_origin(R{}), Rep> operator()(FwdRep&& lhs) const
|
||||
{
|
||||
return quantity_point{quantity{std::forward<Rep>(lhs), R{}}};
|
||||
return quantity_point{quantity{std::forward<FwdRep>(lhs), R{}}};
|
||||
}
|
||||
};
|
||||
|
||||
MP_UNITS_EXPORT_BEGIN
|
||||
|
||||
template<Reference auto R>
|
||||
inline constexpr delta_<MP_UNITS_REMOVE_CONST(decltype(R))> delta{};
|
||||
constexpr delta_<MP_UNITS_REMOVE_CONST(decltype(R))> delta{};
|
||||
|
||||
template<Reference auto R>
|
||||
inline constexpr absolute_<MP_UNITS_REMOVE_CONST(decltype(R))> absolute{};
|
||||
constexpr absolute_<MP_UNITS_REMOVE_CONST(decltype(R))> absolute{};
|
||||
|
||||
MP_UNITS_EXPORT_END
|
||||
|
||||
|
@@ -50,11 +50,11 @@ MP_UNITS_EXPORT_BEGIN
|
||||
* @tparam Rep a representation type for which a type trait is defined
|
||||
*/
|
||||
template<typename Rep>
|
||||
inline constexpr bool treat_as_floating_point = std::is_floating_point_v<Rep>;
|
||||
constexpr bool treat_as_floating_point = std::is_floating_point_v<Rep>;
|
||||
|
||||
template<typename Rep>
|
||||
requires requires { typename wrapped_type_t<Rep>; }
|
||||
inline constexpr bool treat_as_floating_point<Rep> = treat_as_floating_point<wrapped_type_t<Rep>>;
|
||||
constexpr bool treat_as_floating_point<Rep> = treat_as_floating_point<wrapped_type_t<Rep>>;
|
||||
|
||||
/**
|
||||
* @brief Specifies a type to have a scalar character
|
||||
@@ -62,7 +62,7 @@ inline constexpr bool treat_as_floating_point<Rep> = treat_as_floating_point<wra
|
||||
* A scalar is a physical quantity that has magnitude but no direction.
|
||||
*/
|
||||
template<typename Rep>
|
||||
inline constexpr bool is_scalar = std::is_floating_point_v<Rep> || (std::is_integral_v<Rep> && !is_same_v<Rep, bool>);
|
||||
constexpr bool is_scalar = std::is_floating_point_v<Rep> || (std::is_integral_v<Rep> && !is_same_v<Rep, bool>);
|
||||
|
||||
/**
|
||||
* @brief Specifies a type to have a vector character
|
||||
@@ -76,11 +76,11 @@ inline constexpr bool is_scalar = std::is_floating_point_v<Rep> || (std::is_inte
|
||||
* @code{.cpp}
|
||||
* template<class T>
|
||||
* requires mp_units::is_scalar<T>
|
||||
* inline constexpr bool mp_units::is_vector<T> = true;
|
||||
* constexpr bool mp_units::is_vector<T> = true;
|
||||
* @endcode
|
||||
*/
|
||||
template<typename Rep>
|
||||
inline constexpr bool is_vector = false;
|
||||
constexpr bool is_vector = false;
|
||||
|
||||
/**
|
||||
* @brief Specifies a type to have a tensor character
|
||||
@@ -91,7 +91,7 @@ inline constexpr bool is_vector = false;
|
||||
* Similarly to `is_vector` a partial specialization is needed in such cases.
|
||||
*/
|
||||
template<typename Rep>
|
||||
inline constexpr bool is_tensor = false;
|
||||
constexpr bool is_tensor = false;
|
||||
|
||||
/**
|
||||
* @brief A type trait that defines zero, one, min, and max for a representation type
|
||||
|
@@ -53,7 +53,7 @@ template<symbol_text Symbol>
|
||||
void to_base_specialization_of_base_dimension(const volatile base_dimension<Symbol>*);
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_derived_from_specialization_of_base_dimension =
|
||||
constexpr bool is_derived_from_specialization_of_base_dimension =
|
||||
requires(T* type) { to_base_specialization_of_base_dimension(type); };
|
||||
|
||||
/**
|
||||
@@ -68,16 +68,16 @@ template<typename T>
|
||||
struct is_dimension_one : std::false_type {};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_power_of_dim = requires {
|
||||
constexpr bool is_power_of_dim = requires {
|
||||
requires is_specialization_of_power<T> &&
|
||||
(BaseDimension<typename T::factor> || is_dimension_one<typename T::factor>::value);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_per_of_dims = false;
|
||||
constexpr bool is_per_of_dims = false;
|
||||
|
||||
template<typename... Ts>
|
||||
inline constexpr bool is_per_of_dims<per<Ts...>> =
|
||||
constexpr bool is_per_of_dims<per<Ts...>> =
|
||||
(... && (BaseDimension<Ts> || is_dimension_one<Ts>::value || is_power_of_dim<Ts>));
|
||||
|
||||
template<typename T>
|
||||
|
@@ -57,37 +57,37 @@ struct per {};
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_specialization_of_per = false;
|
||||
constexpr bool is_specialization_of_per = false;
|
||||
|
||||
template<typename... Ts>
|
||||
inline constexpr bool is_specialization_of_per<per<Ts...>> = true;
|
||||
constexpr bool is_specialization_of_per<per<Ts...>> = true;
|
||||
|
||||
template<int Num, int... Den>
|
||||
inline constexpr bool valid_ratio = true;
|
||||
constexpr bool valid_ratio = true;
|
||||
|
||||
template<int... Den>
|
||||
inline constexpr bool valid_ratio<0, Den...> = false;
|
||||
constexpr bool valid_ratio<0, Den...> = false;
|
||||
|
||||
template<int Num>
|
||||
inline constexpr bool valid_ratio<Num, 0> = false;
|
||||
constexpr bool valid_ratio<Num, 0> = false;
|
||||
|
||||
template<>
|
||||
inline constexpr bool valid_ratio<0, 0> = false;
|
||||
MP_UNITS_INLINE constexpr bool valid_ratio<0, 0> = false;
|
||||
|
||||
template<int Num, int... Den>
|
||||
inline constexpr bool positive_ratio = gt_zero<Num>;
|
||||
constexpr bool positive_ratio = gt_zero<Num>;
|
||||
|
||||
template<int Num, int Den>
|
||||
inline constexpr bool positive_ratio<Num, Den> = gt_zero<Num * Den>;
|
||||
constexpr bool positive_ratio<Num, Den> = gt_zero<Num * Den>;
|
||||
|
||||
template<int Num, int... Den>
|
||||
inline constexpr bool ratio_one = false;
|
||||
constexpr bool ratio_one = false;
|
||||
|
||||
template<>
|
||||
inline constexpr bool ratio_one<1> = true;
|
||||
MP_UNITS_INLINE constexpr bool ratio_one<1> = true;
|
||||
|
||||
template<int N>
|
||||
inline constexpr bool ratio_one<N, N> = true;
|
||||
constexpr bool ratio_one<N, N> = true;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -127,10 +127,10 @@ using expr_type = detail::expr_type_impl<T>::type;
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_specialization_of_power = false;
|
||||
constexpr bool is_specialization_of_power = false;
|
||||
|
||||
template<typename F, int... Ints>
|
||||
inline constexpr bool is_specialization_of_power<power<F, Ints...>> = true;
|
||||
constexpr bool is_specialization_of_power<power<F, Ints...>> = true;
|
||||
|
||||
template<typename T, ratio R>
|
||||
consteval auto power_or_T_impl()
|
||||
@@ -508,10 +508,10 @@ concept expr_type_projectable = (requires { typename Proj<T>; } ||
|
||||
(is_specialization_of_power<T> && requires { typename Proj<typename T::factor>; }));
|
||||
|
||||
template<typename T, template<typename> typename Proj>
|
||||
inline constexpr bool expr_projectable_impl = false;
|
||||
constexpr bool expr_projectable_impl = false;
|
||||
|
||||
template<typename... Ts, template<typename> typename Proj>
|
||||
inline constexpr bool expr_projectable_impl<type_list<Ts...>, Proj> = (... && expr_type_projectable<Ts, Proj>);
|
||||
constexpr bool expr_projectable_impl<type_list<Ts...>, Proj> = (... && expr_type_projectable<Ts, Proj>);
|
||||
|
||||
template<typename T, template<typename> typename Proj>
|
||||
concept expr_projectable = requires {
|
||||
|
@@ -59,10 +59,10 @@ using factorizer = wheel_factorizer<4>;
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_magnitude = false;
|
||||
constexpr bool is_magnitude = false;
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_specialization_of_magnitude = false;
|
||||
constexpr bool is_specialization_of_magnitude = false;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -87,7 +87,7 @@ concept Magnitude = detail::is_magnitude<T>;
|
||||
// void to_base_specialization_of_constant(const volatile constant<V>*);
|
||||
|
||||
// template<typename T>
|
||||
// inline constexpr bool is_derived_from_specialization_of_constant =
|
||||
// constexpr bool is_derived_from_specialization_of_constant =
|
||||
// requires(T * t) { to_base_specialization_of_constant(t); };
|
||||
|
||||
// } // namespace detail
|
||||
@@ -142,7 +142,7 @@ concept Magnitude = detail::is_magnitude<T>;
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_named_magnitude = Magnitude<T> && !detail::is_specialization_of_magnitude<T>;
|
||||
constexpr bool is_named_magnitude = Magnitude<T> && !detail::is_specialization_of_magnitude<T>;
|
||||
|
||||
}
|
||||
|
||||
@@ -178,10 +178,10 @@ struct power_v {
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_specialization_of_power_v = false;
|
||||
constexpr bool is_specialization_of_power_v = false;
|
||||
|
||||
template<auto V, int... Ints>
|
||||
inline constexpr bool is_specialization_of_power_v<power_v<V, Ints...>> = true;
|
||||
constexpr bool is_specialization_of_power_v<power_v<V, Ints...>> = true;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -572,13 +572,13 @@ namespace detail {
|
||||
// }
|
||||
|
||||
// template<MagnitudeSpec auto... Elements>
|
||||
// inline constexpr bool all_elements_valid = (is_valid_element(Elements) && ...);
|
||||
// constexpr bool all_elements_valid = (is_valid_element(Elements) && ...);
|
||||
|
||||
// template<MagnitudeSpec auto... Elements>
|
||||
// inline constexpr bool all_elements_in_order = strictly_increasing(get_base_value(Elements)...);
|
||||
// constexpr bool all_elements_in_order = strictly_increasing(get_base_value(Elements)...);
|
||||
|
||||
// template<MagnitudeSpec auto... Elements>
|
||||
// inline constexpr bool is_element_pack_valid = all_elements_valid<Elements...> && all_elements_in_order<Elements...>;
|
||||
// constexpr bool is_element_pack_valid = all_elements_valid<Elements...> && all_elements_in_order<Elements...>;
|
||||
|
||||
[[nodiscard]] consteval bool is_rational(MagnitudeSpec auto element)
|
||||
{
|
||||
@@ -707,15 +707,15 @@ template<auto... Ms>
|
||||
void to_base_specialization_of_magnitude(const volatile magnitude<Ms...>*);
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_derived_from_specialization_of_magnitude =
|
||||
constexpr bool is_derived_from_specialization_of_magnitude =
|
||||
requires(T* type) { to_base_specialization_of_magnitude(type); };
|
||||
|
||||
template<typename T>
|
||||
requires is_derived_from_specialization_of_magnitude<T>
|
||||
inline constexpr bool is_magnitude<T> = true;
|
||||
constexpr bool is_magnitude<T> = true;
|
||||
|
||||
template<auto... Ms>
|
||||
inline constexpr bool is_specialization_of_magnitude<magnitude<Ms...>> = true;
|
||||
constexpr bool is_specialization_of_magnitude<magnitude<Ms...>> = true;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -882,7 +882,7 @@ using common_magnitude_type = decltype(common_magnitude_type_impl(M));
|
||||
//
|
||||
// WARNING: The program behaviour will be undefined if you provide a wrong answer, so check your math!
|
||||
MP_UNITS_EXPORT template<std::intmax_t N>
|
||||
inline constexpr std::optional<std::intmax_t> known_first_factor = std::nullopt;
|
||||
constexpr std::optional<std::intmax_t> known_first_factor = std::nullopt;
|
||||
|
||||
namespace detail {
|
||||
|
||||
@@ -915,7 +915,7 @@ struct prime_factorization<1> {
|
||||
};
|
||||
|
||||
template<std::intmax_t N>
|
||||
inline constexpr auto prime_factorization_v = prime_factorization<N>::value;
|
||||
constexpr auto prime_factorization_v = prime_factorization<N>::value;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -927,18 +927,18 @@ inline constexpr auto prime_factorization_v = prime_factorization<N>::value;
|
||||
*/
|
||||
MP_UNITS_EXPORT template<std::intmax_t V>
|
||||
requires detail::gt_zero<V>
|
||||
inline constexpr Magnitude auto mag = detail::prime_factorization_v<V>;
|
||||
constexpr Magnitude auto mag = detail::prime_factorization_v<V>;
|
||||
|
||||
MP_UNITS_EXPORT template<std::intmax_t N, std::intmax_t D>
|
||||
requires detail::gt_zero<N>
|
||||
inline constexpr Magnitude auto mag_ratio = detail::prime_factorization_v<N> / detail::prime_factorization_v<D>;
|
||||
constexpr Magnitude auto mag_ratio = detail::prime_factorization_v<N> / detail::prime_factorization_v<D>;
|
||||
|
||||
/**
|
||||
* @brief Create a Magnitude which is some rational number raised to a rational power.
|
||||
*/
|
||||
MP_UNITS_EXPORT template<std::intmax_t Base, std::intmax_t Pow>
|
||||
requires detail::gt_zero<Base>
|
||||
inline constexpr Magnitude auto mag_power = pow<Pow>(mag<Base>);
|
||||
constexpr Magnitude auto mag_power = pow<Pow>(mag<Base>);
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
@@ -168,22 +168,23 @@ public:
|
||||
quantity(quantity&&) = default;
|
||||
~quantity() = default;
|
||||
|
||||
template<typename Value, Reference R2>
|
||||
requires detail::SameValueAs<R2{}, R, std::remove_cvref_t<Value>, Rep>
|
||||
constexpr quantity(Value&& v, R2) : numerical_value_is_an_implementation_detail_(std::forward<Value>(v))
|
||||
template<typename FwdValue, Reference R2>
|
||||
requires detail::SameValueAs<R2{}, R, std::remove_cvref_t<FwdValue>, Rep>
|
||||
constexpr quantity(FwdValue&& v, R2) : numerical_value_is_an_implementation_detail_(std::forward<FwdValue>(v))
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Value, Reference R2>
|
||||
requires(!detail::SameValueAs<R2{}, R, std::remove_cvref_t<Value>, Rep>) &&
|
||||
detail::QuantityConvertibleTo<quantity<R2{}, std::remove_cvref_t<Value>>, quantity>
|
||||
constexpr quantity(Value&& v, R2) : quantity(quantity<R2{}, std::remove_cvref_t<Value>>{std::forward<Value>(v), R2{}})
|
||||
template<typename FwdValue, Reference R2, typename Value = std::remove_cvref_t<FwdValue>>
|
||||
requires(!detail::SameValueAs<R2{}, R, Value, Rep>) &&
|
||||
detail::QuantityConvertibleTo<quantity<R2{}, Value>, quantity>
|
||||
constexpr quantity(FwdValue&& v, R2) : quantity(quantity<R2{}, Value>{std::forward<FwdValue>(v), R2{}})
|
||||
{
|
||||
}
|
||||
|
||||
template<detail::ValuePreservingTo<Rep> Value>
|
||||
template<detail::ValuePreservingTo<Rep> FwdValue>
|
||||
requires(unit == ::mp_units::one)
|
||||
constexpr explicit(false) quantity(Value&& v) : numerical_value_is_an_implementation_detail_(std::forward<Value>(v))
|
||||
constexpr explicit(false) quantity(FwdValue&& v) :
|
||||
numerical_value_is_an_implementation_detail_(std::forward<FwdValue>(v))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -209,11 +210,11 @@ public:
|
||||
quantity& operator=(const quantity&) = default;
|
||||
quantity& operator=(quantity&&) = default;
|
||||
|
||||
template<detail::ValuePreservingTo<Rep> Value>
|
||||
template<detail::ValuePreservingTo<Rep> FwdValue>
|
||||
requires(unit == ::mp_units::one)
|
||||
constexpr quantity& operator=(Value&& v)
|
||||
constexpr quantity& operator=(FwdValue&& v)
|
||||
{
|
||||
numerical_value_is_an_implementation_detail_ = std::forward<Value>(v);
|
||||
numerical_value_is_an_implementation_detail_ = std::forward<FwdValue>(v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -355,16 +356,16 @@ public:
|
||||
return ::mp_units::quantity{-numerical_value_is_an_implementation_detail_, reference};
|
||||
}
|
||||
|
||||
template<typename Q>
|
||||
friend constexpr decltype(auto) operator++(Q&& q)
|
||||
requires std::derived_from<std::remove_cvref_t<Q>, quantity> && requires(rep v) {
|
||||
template<typename FwdQ, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>>
|
||||
friend constexpr decltype(auto) operator++(FwdQ&& q)
|
||||
requires requires(rep v) {
|
||||
{
|
||||
++v
|
||||
} -> std::same_as<rep&>;
|
||||
}
|
||||
{
|
||||
++q.numerical_value_is_an_implementation_detail_;
|
||||
return std::forward<Q>(q);
|
||||
return std::forward<FwdQ>(q);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr QuantityOf<quantity_spec> auto operator++(int)
|
||||
@@ -377,16 +378,16 @@ public:
|
||||
return ::mp_units::quantity{numerical_value_is_an_implementation_detail_++, reference};
|
||||
}
|
||||
|
||||
template<typename Q>
|
||||
friend constexpr decltype(auto) operator--(Q&& q)
|
||||
requires std::derived_from<std::remove_cvref_t<Q>, quantity> && requires(rep v) {
|
||||
template<typename FwdQ, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>>
|
||||
friend constexpr decltype(auto) operator--(FwdQ&& q)
|
||||
requires requires(rep v) {
|
||||
{
|
||||
--v
|
||||
} -> std::same_as<rep&>;
|
||||
}
|
||||
{
|
||||
--q.numerical_value_is_an_implementation_detail_;
|
||||
return std::forward<Q>(q);
|
||||
return std::forward<FwdQ>(q);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr QuantityOf<quantity_spec> auto operator--(int)
|
||||
@@ -400,99 +401,94 @@ public:
|
||||
}
|
||||
|
||||
// compound assignment operators
|
||||
template<typename Q>
|
||||
requires std::derived_from<std::remove_cvref_t<Q>, quantity> && requires(rep a, rep b) {
|
||||
template<typename FwdQ, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>>
|
||||
requires requires(rep a, rep b) {
|
||||
{
|
||||
a += b
|
||||
} -> std::same_as<rep&>;
|
||||
}
|
||||
friend constexpr decltype(auto) operator+=(Q&& lhs, const quantity& rhs)
|
||||
friend constexpr decltype(auto) operator+=(FwdQ&& lhs, const quantity& rhs)
|
||||
{
|
||||
lhs.numerical_value_is_an_implementation_detail_ += rhs.numerical_value_is_an_implementation_detail_;
|
||||
return std::forward<Q>(lhs);
|
||||
return std::forward<FwdQ>(lhs);
|
||||
}
|
||||
|
||||
template<typename Q>
|
||||
requires std::derived_from<std::remove_cvref_t<Q>, quantity> && requires(rep a, rep b) {
|
||||
template<typename FwdQ, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>>
|
||||
requires requires(rep a, rep b) {
|
||||
{
|
||||
a -= b
|
||||
} -> std::same_as<rep&>;
|
||||
}
|
||||
friend constexpr decltype(auto) operator-=(Q&& lhs, const quantity& rhs)
|
||||
friend constexpr decltype(auto) operator-=(FwdQ&& lhs, const quantity& rhs)
|
||||
{
|
||||
lhs.numerical_value_is_an_implementation_detail_ -= rhs.numerical_value_is_an_implementation_detail_;
|
||||
return std::forward<Q>(lhs);
|
||||
return std::forward<FwdQ>(lhs);
|
||||
}
|
||||
|
||||
template<typename Q>
|
||||
requires std::derived_from<std::remove_cvref_t<Q>, quantity> && (!treat_as_floating_point<rep>) &&
|
||||
requires(rep a, rep b) {
|
||||
{
|
||||
a %= b
|
||||
} -> std::same_as<rep&>;
|
||||
}
|
||||
friend constexpr decltype(auto) operator%=(Q&& lhs, const quantity& rhs)
|
||||
template<typename FwdQ, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>>
|
||||
requires(!treat_as_floating_point<rep>) && requires(rep a, rep b) {
|
||||
{
|
||||
a %= b
|
||||
} -> std::same_as<rep&>;
|
||||
}
|
||||
friend constexpr decltype(auto) operator%=(FwdQ&& lhs, const quantity& rhs)
|
||||
|
||||
{
|
||||
MP_UNITS_EXPECTS_DEBUG(rhs != zero());
|
||||
lhs.numerical_value_is_an_implementation_detail_ %= rhs.numerical_value_is_an_implementation_detail_;
|
||||
return std::forward<Q>(lhs);
|
||||
return std::forward<FwdQ>(lhs);
|
||||
}
|
||||
|
||||
template<typename Q, typename Value>
|
||||
requires std::derived_from<std::remove_cvref_t<Q>, quantity> && (!Quantity<Value>) &&
|
||||
requires(rep a, const Value b) {
|
||||
{
|
||||
a *= b
|
||||
} -> std::same_as<rep&>;
|
||||
}
|
||||
friend constexpr decltype(auto) operator*=(Q&& lhs, const Value& v)
|
||||
template<typename FwdQ, typename Value, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>>
|
||||
requires(!Quantity<Value>) && requires(rep a, const Value b) {
|
||||
{
|
||||
a *= b
|
||||
} -> std::same_as<rep&>;
|
||||
}
|
||||
friend constexpr decltype(auto) operator*=(FwdQ&& lhs, const Value& v)
|
||||
{
|
||||
lhs.numerical_value_is_an_implementation_detail_ = lhs.numerical_value_is_an_implementation_detail_ * v;
|
||||
return std::forward<Q>(lhs);
|
||||
return std::forward<FwdQ>(lhs);
|
||||
}
|
||||
|
||||
template<typename Q1, QuantityOf<dimensionless> Q2>
|
||||
requires std::derived_from<std::remove_cvref_t<Q1>, quantity> && (Q2::unit == ::mp_units::one) &&
|
||||
requires(rep a, const typename Q2::rep b) {
|
||||
{
|
||||
a *= b
|
||||
} -> std::same_as<rep&>;
|
||||
}
|
||||
friend constexpr decltype(auto) operator*=(Q1&& lhs, const Q2& rhs)
|
||||
template<typename FwdQ1, QuantityOf<dimensionless> Q2, std::derived_from<quantity> Q1 = std::remove_cvref_t<FwdQ1>>
|
||||
requires(Q2::unit == ::mp_units::one) && requires(rep a, const typename Q2::rep b) {
|
||||
{
|
||||
a *= b
|
||||
} -> std::same_as<rep&>;
|
||||
}
|
||||
friend constexpr decltype(auto) operator*=(FwdQ1&& lhs, const Q2& rhs)
|
||||
{
|
||||
lhs.numerical_value_is_an_implementation_detail_ =
|
||||
lhs.numerical_value_is_an_implementation_detail_ * rhs.numerical_value_is_an_implementation_detail_;
|
||||
return std::forward<Q1>(lhs);
|
||||
return std::forward<FwdQ1>(lhs);
|
||||
}
|
||||
|
||||
template<typename Q, typename Value>
|
||||
requires std::derived_from<std::remove_cvref_t<Q>, quantity> && (!Quantity<Value>) &&
|
||||
requires(rep a, const Value b) {
|
||||
{
|
||||
a /= b
|
||||
} -> std::same_as<rep&>;
|
||||
}
|
||||
friend constexpr decltype(auto) operator/=(Q&& lhs, const Value& v)
|
||||
template<typename FwdQ, typename Value, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>>
|
||||
requires(!Quantity<Value>) && requires(rep a, const Value b) {
|
||||
{
|
||||
a /= b
|
||||
} -> std::same_as<rep&>;
|
||||
}
|
||||
friend constexpr decltype(auto) operator/=(FwdQ&& lhs, const Value& v)
|
||||
{
|
||||
MP_UNITS_EXPECTS_DEBUG(v != quantity_values<Value>::zero());
|
||||
lhs.numerical_value_is_an_implementation_detail_ = lhs.numerical_value_is_an_implementation_detail_ / v;
|
||||
return std::forward<Q>(lhs);
|
||||
return std::forward<FwdQ>(lhs);
|
||||
}
|
||||
|
||||
template<typename Q1, QuantityOf<dimensionless> Q2>
|
||||
requires std::derived_from<std::remove_cvref_t<Q1>, quantity> && (Q2::unit == ::mp_units::one) &&
|
||||
requires(rep a, const typename Q2::rep b) {
|
||||
{
|
||||
a /= b
|
||||
} -> std::same_as<rep&>;
|
||||
}
|
||||
friend constexpr decltype(auto) operator/=(Q1&& lhs, const Q2& rhs)
|
||||
template<typename FwdQ1, QuantityOf<dimensionless> Q2, std::derived_from<quantity> Q1 = std::remove_cvref_t<FwdQ1>>
|
||||
requires(Q2::unit == ::mp_units::one) && requires(rep a, const typename Q2::rep b) {
|
||||
{
|
||||
a /= b
|
||||
} -> std::same_as<rep&>;
|
||||
}
|
||||
friend constexpr decltype(auto) operator/=(FwdQ1&& lhs, const Q2& rhs)
|
||||
{
|
||||
MP_UNITS_EXPECTS_DEBUG(rhs != rhs.zero());
|
||||
lhs.numerical_value_is_an_implementation_detail_ =
|
||||
lhs.numerical_value_is_an_implementation_detail_ / rhs.numerical_value_is_an_implementation_detail_;
|
||||
return std::forward<Q1>(lhs);
|
||||
return std::forward<FwdQ1>(lhs);
|
||||
}
|
||||
|
||||
// binary operators on quantities
|
||||
|
@@ -56,13 +56,11 @@ namespace mp_units {
|
||||
*
|
||||
* @tparam ToQS a quantity specification to use for a target quantity
|
||||
*/
|
||||
template<QuantitySpec auto ToQS, typename Q>
|
||||
requires Quantity<std::remove_cvref_t<Q>> &&
|
||||
detail::QuantitySpecCastableTo<std::remove_reference_t<Q>::quantity_spec, ToQS>
|
||||
[[nodiscard]] constexpr Quantity auto quantity_cast(Q&& q)
|
||||
template<QuantitySpec auto ToQS, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>>
|
||||
requires detail::QuantitySpecCastableTo<Q::quantity_spec, ToQS>
|
||||
[[nodiscard]] constexpr Quantity auto quantity_cast(FwdQ&& q)
|
||||
{
|
||||
return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_,
|
||||
make_reference(ToQS, std::remove_reference_t<Q>::unit)};
|
||||
return quantity{std::forward<FwdQ>(q).numerical_value_is_an_implementation_detail_, make_reference(ToQS, Q::unit)};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,13 +80,12 @@ template<QuantitySpec auto ToQS, typename Q>
|
||||
*
|
||||
* @tparam ToQS a quantity specification to use for a target quantity point
|
||||
*/
|
||||
template<QuantitySpec auto ToQS, typename QP>
|
||||
requires QuantityPoint<std::remove_cvref_t<QP>> &&
|
||||
detail::QuantitySpecCastableTo<std::remove_reference_t<QP>::quantity_spec, ToQS>
|
||||
[[nodiscard]] constexpr QuantityPoint auto quantity_cast(QP&& qp)
|
||||
template<QuantitySpec auto ToQS, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<FwdQP>>
|
||||
requires detail::QuantitySpecCastableTo<QP::quantity_spec, ToQS>
|
||||
[[nodiscard]] constexpr QuantityPoint auto quantity_cast(FwdQP&& qp)
|
||||
{
|
||||
return QP{quantity_cast<ToQS>(std::forward<QP>(qp).quantity_from_origin_is_an_implementation_detail_),
|
||||
std::remove_reference_t<QP>::point_origin};
|
||||
return QP{quantity_cast<ToQS>(std::forward<FwdQP>(qp).quantity_from_origin_is_an_implementation_detail_),
|
||||
QP::point_origin};
|
||||
}
|
||||
|
||||
} // namespace mp_units
|
||||
|
@@ -40,7 +40,7 @@ template<auto R, typename Rep>
|
||||
void to_base_specialization_of_quantity(const volatile quantity<R, Rep>*);
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_derived_from_specialization_of_quantity =
|
||||
constexpr bool is_derived_from_specialization_of_quantity =
|
||||
requires(T* type) { to_base_specialization_of_quantity(type); };
|
||||
|
||||
} // namespace detail
|
||||
|
@@ -43,7 +43,7 @@ namespace mp_units {
|
||||
namespace detail {
|
||||
|
||||
template<PointOrigin PO>
|
||||
inline constexpr bool is_specialization_of_zeroth_point_origin = false;
|
||||
constexpr bool is_specialization_of_zeroth_point_origin = false;
|
||||
|
||||
template<PointOrigin PO>
|
||||
[[nodiscard]] consteval bool is_zeroth_point_origin(PO)
|
||||
@@ -52,20 +52,16 @@ template<PointOrigin PO>
|
||||
}
|
||||
|
||||
struct point_origin_interface {
|
||||
template<PointOrigin PO, Quantity Q>
|
||||
requires ReferenceOf<std::remove_const_t<decltype(Q::reference)>, PO::quantity_spec>
|
||||
[[nodiscard]] friend constexpr quantity_point<Q::reference, MP_UNITS_EXPRESSION_WORKAROUND(PO{}), typename Q::rep>
|
||||
operator+(PO, Q&& q)
|
||||
template<PointOrigin PO, typename FwdQ, QuantityOf<PO::quantity_spec> Q = std::remove_cvref_t<FwdQ>>
|
||||
[[nodiscard]] friend constexpr quantity_point<Q::reference, MP_UNITS_EXPRESSION_WORKAROUND(PO{}), typename Q::rep> operator+(PO, FwdQ&& q)
|
||||
{
|
||||
return quantity_point{std::forward<Q>(q), PO{}};
|
||||
return quantity_point{std::forward<FwdQ>(q), PO{}};
|
||||
}
|
||||
|
||||
template<Quantity Q, PointOrigin PO>
|
||||
requires ReferenceOf<std::remove_const_t<decltype(Q::reference)>, PO::quantity_spec>
|
||||
[[nodiscard]] friend constexpr quantity_point<Q::reference, MP_UNITS_EXPRESSION_WORKAROUND(PO{}), typename Q::rep>
|
||||
operator+(Q&& q, PO po)
|
||||
template<Quantity FwdQ, PointOrigin PO, QuantityOf<PO::quantity_spec> Q = std::remove_cvref_t<FwdQ>>
|
||||
[[nodiscard]] friend constexpr quantity_point<Q::reference, MP_UNITS_EXPRESSION_WORKAROUND(PO{}), typename Q::rep> operator+(FwdQ&& q, PO po)
|
||||
{
|
||||
return po + std::forward<Q>(q);
|
||||
return po + std::forward<FwdQ>(q);
|
||||
}
|
||||
|
||||
template<PointOrigin PO, Quantity Q>
|
||||
@@ -132,12 +128,12 @@ template<QuantitySpec auto QS>
|
||||
struct zeroth_point_origin_ final : absolute_point_origin<QS> {};
|
||||
|
||||
MP_UNITS_EXPORT template<QuantitySpec auto QS>
|
||||
inline constexpr zeroth_point_origin_<QS> zeroth_point_origin;
|
||||
constexpr zeroth_point_origin_<QS> zeroth_point_origin;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<auto QS>
|
||||
inline constexpr bool is_specialization_of_zeroth_point_origin<zeroth_point_origin_<QS>> = true;
|
||||
constexpr bool is_specialization_of_zeroth_point_origin<zeroth_point_origin_<QS>> = true;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -208,27 +204,26 @@ public:
|
||||
quantity_point(quantity_point&&) = default;
|
||||
~quantity_point() = default;
|
||||
|
||||
template<typename Q>
|
||||
requires QuantityOf<std::remove_cvref_t<Q>, quantity_spec> && std::constructible_from<quantity_type, Q> &&
|
||||
(point_origin == default_point_origin(R)) && (implicitly_convertible(Q::quantity_spec, quantity_spec))
|
||||
constexpr explicit quantity_point(Q&& q) : quantity_from_origin_is_an_implementation_detail_(std::forward<Q>(q))
|
||||
template<typename FwdQ, QuantityOf<quantity_spec> Q = std::remove_cvref_t<FwdQ>>
|
||||
requires std::constructible_from<quantity_type, FwdQ> && (point_origin == default_point_origin(R)) &&
|
||||
(implicitly_convertible(Q::quantity_spec, quantity_spec))
|
||||
constexpr explicit quantity_point(FwdQ&& q) : quantity_from_origin_is_an_implementation_detail_(std::forward<FwdQ>(q))
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Q>
|
||||
requires QuantityOf<std::remove_cvref_t<Q>, quantity_spec> && std::constructible_from<quantity_type, Q>
|
||||
constexpr quantity_point(Q&& q, decltype(PO)) : quantity_from_origin_is_an_implementation_detail_(std::forward<Q>(q))
|
||||
template<typename FwdQ, QuantityOf<quantity_spec> Q = std::remove_cvref_t<FwdQ>>
|
||||
requires std::constructible_from<quantity_type, FwdQ>
|
||||
constexpr quantity_point(FwdQ&& q, decltype(PO)) :
|
||||
quantity_from_origin_is_an_implementation_detail_(std::forward<FwdQ>(q))
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Q, PointOrigin PO2>
|
||||
requires Quantity<std::remove_cvref_t<Q>> && std::constructible_from<quantity_type, Q> &&
|
||||
ReferenceOf<std::remove_const_t<decltype(std::remove_reference_t<Q>::reference)>, PO2::quantity_spec> &&
|
||||
detail::SameAbsolutePointOriginAs<PO2, PO>
|
||||
constexpr quantity_point(Q&& q, PO2) :
|
||||
template<typename FwdQ, PointOrigin PO2, QuantityOf<PO2::quantity_spec> Q = std::remove_cvref_t<FwdQ>>
|
||||
requires std::constructible_from<quantity_type, FwdQ> && detail::SameAbsolutePointOriginAs<PO2, PO>
|
||||
constexpr quantity_point(FwdQ&& q, PO2) :
|
||||
quantity_point(
|
||||
quantity_point<std::remove_reference_t<Q>::reference, PO2{}, typename std::remove_reference_t<Q>::rep>{
|
||||
std::forward<Q>(q), PO2{}})
|
||||
std::forward<FwdQ>(q), PO2{}})
|
||||
{
|
||||
}
|
||||
|
||||
@@ -299,7 +294,7 @@ public:
|
||||
#endif
|
||||
|
||||
template<PointOrigin PO2>
|
||||
requires requires { quantity_point{} - PO2{}; }
|
||||
requires requires(quantity_point qp) { qp - PO2{}; }
|
||||
[[nodiscard]] constexpr Quantity auto quantity_from(PO2) const
|
||||
{
|
||||
return *this - PO2{};
|
||||
@@ -414,13 +409,12 @@ public:
|
||||
}
|
||||
|
||||
// member unary operators
|
||||
template<typename QP>
|
||||
friend constexpr decltype(auto) operator++(QP&& qp)
|
||||
requires std::derived_from<std::remove_cvref_t<QP>, quantity_point> &&
|
||||
requires { ++qp.quantity_from_origin_is_an_implementation_detail_; }
|
||||
template<typename FwdQP, std::derived_from<quantity_point> QP = std::remove_cvref_t<FwdQP>>
|
||||
friend constexpr decltype(auto) operator++(FwdQP&& qp)
|
||||
requires requires { ++qp.quantity_from_origin_is_an_implementation_detail_; }
|
||||
{
|
||||
++qp.quantity_from_origin_is_an_implementation_detail_;
|
||||
return std::forward<QP>(qp);
|
||||
return std::forward<FwdQP>(qp);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr quantity_point operator++(int)
|
||||
@@ -429,13 +423,12 @@ public:
|
||||
return {quantity_from_origin_is_an_implementation_detail_++, PO};
|
||||
}
|
||||
|
||||
template<typename QP>
|
||||
friend constexpr decltype(auto) operator--(QP&& qp)
|
||||
requires std::derived_from<std::remove_cvref_t<QP>, quantity_point> &&
|
||||
requires { --qp.quantity_from_origin_is_an_implementation_detail_; }
|
||||
template<typename FwdQP, std::derived_from<quantity_point> QP = std::remove_cvref_t<FwdQP>>
|
||||
friend constexpr decltype(auto) operator--(FwdQP&& qp)
|
||||
requires requires { --qp.quantity_from_origin_is_an_implementation_detail_; }
|
||||
{
|
||||
--qp.quantity_from_origin_is_an_implementation_detail_;
|
||||
return std::forward<QP>(qp);
|
||||
return std::forward<FwdQP>(qp);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr quantity_point operator--(int)
|
||||
@@ -445,22 +438,20 @@ public:
|
||||
}
|
||||
|
||||
// compound assignment operators
|
||||
template<typename QP>
|
||||
requires std::derived_from<std::remove_cvref_t<QP>, quantity_point> &&
|
||||
requires(quantity_type q) { quantity_from_origin_is_an_implementation_detail_ += q; }
|
||||
friend constexpr decltype(auto) operator+=(QP&& qp, const quantity_type& q)
|
||||
template<typename FwdQP, std::derived_from<quantity_point> QP = std::remove_cvref_t<FwdQP>>
|
||||
requires requires(quantity_type q) { quantity_from_origin_is_an_implementation_detail_ += q; }
|
||||
friend constexpr decltype(auto) operator+=(FwdQP&& qp, const quantity_type& q)
|
||||
{
|
||||
qp.quantity_from_origin_is_an_implementation_detail_ += q;
|
||||
return std::forward<QP>(qp);
|
||||
return std::forward<FwdQP>(qp);
|
||||
}
|
||||
|
||||
template<typename QP>
|
||||
requires std::derived_from<std::remove_cvref_t<QP>, quantity_point> &&
|
||||
requires(quantity_type q) { quantity_from_origin_is_an_implementation_detail_ -= q; }
|
||||
friend constexpr decltype(auto) operator-=(QP&& qp, const quantity_type& q)
|
||||
template<typename FwdQP, std::derived_from<quantity_point> QP = std::remove_cvref_t<FwdQP>>
|
||||
requires requires(quantity_type q) { quantity_from_origin_is_an_implementation_detail_ -= q; }
|
||||
friend constexpr decltype(auto) operator-=(FwdQP&& qp, const quantity_type& q)
|
||||
{
|
||||
qp.quantity_from_origin_is_an_implementation_detail_ -= q;
|
||||
return std::forward<QP>(qp);
|
||||
return std::forward<FwdQP>(qp);
|
||||
}
|
||||
|
||||
// binary operators on quantity points
|
||||
|
@@ -38,13 +38,13 @@ struct absolute_point_origin;
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_quantity_point = false;
|
||||
constexpr bool is_quantity_point = false;
|
||||
|
||||
template<auto Q>
|
||||
void to_base_specialization_of_absolute_point_origin(const volatile absolute_point_origin<Q>*);
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_derived_from_specialization_of_absolute_point_origin =
|
||||
constexpr bool is_derived_from_specialization_of_absolute_point_origin =
|
||||
requires(T* type) { to_base_specialization_of_absolute_point_origin(type); };
|
||||
|
||||
} // namespace detail
|
||||
@@ -66,7 +66,7 @@ template<auto QP>
|
||||
void to_base_specialization_of_relative_point_origin(const volatile relative_point_origin<QP>*);
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_derived_from_specialization_of_relative_point_origin =
|
||||
constexpr bool is_derived_from_specialization_of_relative_point_origin =
|
||||
requires(T* type) { to_base_specialization_of_relative_point_origin(type); };
|
||||
|
||||
struct point_origin_interface;
|
||||
@@ -99,12 +99,12 @@ template<auto R, auto PO, typename Rep>
|
||||
void to_base_specialization_of_quantity_point(const volatile quantity_point<R, PO, Rep>*);
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_derived_from_specialization_of_quantity_point =
|
||||
constexpr bool is_derived_from_specialization_of_quantity_point =
|
||||
requires(T* type) { to_base_specialization_of_quantity_point(type); };
|
||||
|
||||
template<typename T>
|
||||
requires is_derived_from_specialization_of_quantity_point<T>
|
||||
inline constexpr bool is_quantity_point<T> = true;
|
||||
constexpr bool is_quantity_point<T> = true;
|
||||
|
||||
template<PointOrigin PO1, PointOrigin PO2>
|
||||
[[nodiscard]] consteval bool same_absolute_point_origins(PO1 po1, PO2 po2)
|
||||
|
@@ -159,13 +159,11 @@ struct quantity_spec_interface : quantity_spec_interface_base {
|
||||
return make_reference(self, u);
|
||||
}
|
||||
|
||||
template<typename Self, typename Q>
|
||||
requires Quantity<std::remove_cvref_t<Q>> &&
|
||||
QuantitySpecExplicitlyConvertibleTo<std::remove_reference_t<Q>::quantity_spec, Self{}>
|
||||
[[nodiscard]] constexpr Quantity auto operator()(this Self self, Q&& q)
|
||||
template<typename Self, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>>
|
||||
requires QuantitySpecExplicitlyConvertibleTo<Q::quantity_spec, Self{}>
|
||||
[[nodiscard]] constexpr Quantity auto operator()(this Self self, FwdQ&& q)
|
||||
{
|
||||
return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_,
|
||||
make_reference(self, std::remove_cvref_t<Q>::unit)};
|
||||
return quantity{std::forward<FwdQ>(q).numerical_value_is_an_implementation_detail_, make_reference(self, Q::unit)};
|
||||
}
|
||||
#else
|
||||
template<typename Self_ = Self, UnitOf<Self_{}> U>
|
||||
@@ -174,13 +172,12 @@ struct quantity_spec_interface : quantity_spec_interface_base {
|
||||
return make_reference(Self{}, u);
|
||||
}
|
||||
|
||||
template<typename Q, typename Self_ = Self>
|
||||
requires Quantity<std::remove_cvref_t<Q>> &&
|
||||
QuantitySpecExplicitlyConvertibleTo<std::remove_reference_t<Q>::quantity_spec, Self_{}>
|
||||
[[nodiscard]] constexpr Quantity auto operator()(Q&& q) const
|
||||
template<typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>, typename Self_ = Self>
|
||||
requires QuantitySpecExplicitlyConvertibleTo<Q::quantity_spec, Self_{}>
|
||||
[[nodiscard]] constexpr Quantity auto operator()(FwdQ&& q) const
|
||||
{
|
||||
return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_,
|
||||
make_reference(Self{}, std::remove_cvref_t<Q>::unit)};
|
||||
return quantity{std::forward<FwdQ>(q).numerical_value_is_an_implementation_detail_,
|
||||
make_reference(Self{}, Q::unit)};
|
||||
}
|
||||
#endif
|
||||
};
|
||||
@@ -371,13 +368,12 @@ struct quantity_spec<Self, QS, Args...> : detail::propagate_equation<QS>, detail
|
||||
return detail::make_reference(Self{}, u);
|
||||
}
|
||||
|
||||
template<typename Q, typename Self_ = Self>
|
||||
requires Quantity<std::remove_cvref_t<Q>> &&
|
||||
detail::QuantitySpecExplicitlyConvertibleTo<std::remove_reference_t<Q>::quantity_spec, Self_{}>
|
||||
[[nodiscard]] constexpr Quantity auto operator()(Q&& q) const
|
||||
template<typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>, typename Self_ = Self>
|
||||
requires detail::QuantitySpecExplicitlyConvertibleTo<Q::quantity_spec, Self_{}>
|
||||
[[nodiscard]] constexpr Quantity auto operator()(FwdQ&& q) const
|
||||
{
|
||||
return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_,
|
||||
detail::make_reference(Self{}, std::remove_cvref_t<Q>::unit)};
|
||||
return quantity{std::forward<FwdQ>(q).numerical_value_is_an_implementation_detail_,
|
||||
detail::make_reference(Self{}, Q::unit)};
|
||||
}
|
||||
#endif
|
||||
};
|
||||
@@ -556,7 +552,7 @@ struct kind_of_<Q> final : quantity_spec<kind_of_<Q>, Q{}>::_base_type_ {
|
||||
|
||||
MP_UNITS_EXPORT template<detail::QuantitySpecWithNoSpecifiers auto Q>
|
||||
requires detail::SameQuantitySpec<detail::get_kind_tree_root(Q), Q>
|
||||
inline constexpr kind_of_<MP_UNITS_REMOVE_CONST(decltype(Q))> kind_of;
|
||||
constexpr kind_of_<MP_UNITS_REMOVE_CONST(decltype(Q))> kind_of;
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
@@ -53,10 +53,10 @@ struct kind_of_;
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_specialization_of_kind_of = false;
|
||||
constexpr bool is_specialization_of_kind_of = false;
|
||||
|
||||
template<typename Q>
|
||||
inline constexpr bool is_specialization_of_kind_of<kind_of_<Q>> = true;
|
||||
constexpr bool is_specialization_of_kind_of<kind_of_<Q>> = true;
|
||||
|
||||
template<typename T>
|
||||
concept QuantityKindSpec = is_specialization_of_kind_of<T>;
|
||||
@@ -70,7 +70,7 @@ void to_base_specialization_of_quantity_spec(const volatile quantity_spec<T, Arg
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_derived_from_specialization_of_quantity_spec =
|
||||
constexpr bool is_derived_from_specialization_of_quantity_spec =
|
||||
requires(T* type) { to_base_specialization_of_quantity_spec(type); };
|
||||
|
||||
/**
|
||||
@@ -86,16 +86,16 @@ template<typename T>
|
||||
struct is_dimensionless : std::false_type {};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_power_of_quantity_spec = requires {
|
||||
constexpr bool is_power_of_quantity_spec = requires {
|
||||
requires is_specialization_of_power<T> &&
|
||||
(NamedQuantitySpec<typename T::factor> || is_dimensionless<typename T::factor>::value);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_per_of_quantity_specs = false;
|
||||
constexpr bool is_per_of_quantity_specs = false;
|
||||
|
||||
template<typename... Ts>
|
||||
inline constexpr bool is_per_of_quantity_specs<per<Ts...>> =
|
||||
constexpr bool is_per_of_quantity_specs<per<Ts...>> =
|
||||
(... && (NamedQuantitySpec<Ts> || is_dimensionless<Ts>::value || is_power_of_quantity_spec<Ts>));
|
||||
|
||||
template<typename T>
|
||||
|
@@ -190,36 +190,36 @@ struct reference {
|
||||
};
|
||||
|
||||
|
||||
template<typename Rep, Reference R>
|
||||
requires(!detail::OffsetUnit<decltype(get_unit(R{}))>) &&
|
||||
RepresentationOf<std::remove_cvref_t<Rep>, get_quantity_spec(R{}).character>
|
||||
[[nodiscard]] constexpr quantity<R{}, std::remove_cvref_t<Rep>> operator*(Rep&& lhs, R)
|
||||
template<typename FwdRep, Reference R,
|
||||
RepresentationOf<get_quantity_spec(R{}).character> Rep = std::remove_cvref_t<FwdRep>>
|
||||
requires(!detail::OffsetUnit<decltype(get_unit(R{}))>)
|
||||
[[nodiscard]] constexpr quantity<R{}, Rep> operator*(FwdRep&& lhs, R)
|
||||
{
|
||||
return quantity{std::forward<Rep>(lhs), R{}};
|
||||
return quantity{std::forward<FwdRep>(lhs), R{}};
|
||||
}
|
||||
|
||||
template<typename Rep, Reference R>
|
||||
requires(!detail::OffsetUnit<decltype(get_unit(R{}))>) &&
|
||||
RepresentationOf<std::remove_cvref_t<Rep>, get_quantity_spec(R{}).character>
|
||||
[[nodiscard]] constexpr quantity<inverse(R{}), std::remove_cvref_t<Rep>> operator/(Rep&& lhs, R)
|
||||
template<typename FwdRep, Reference R,
|
||||
RepresentationOf<get_quantity_spec(R{}).character> Rep = std::remove_cvref_t<FwdRep>>
|
||||
requires(!detail::OffsetUnit<decltype(get_unit(R{}))>)
|
||||
[[nodiscard]] constexpr quantity<inverse(R{}), Rep> operator/(FwdRep&& lhs, R)
|
||||
{
|
||||
return quantity{std::forward<Rep>(lhs), inverse(R{})};
|
||||
return quantity{std::forward<FwdRep>(lhs), inverse(R{})};
|
||||
}
|
||||
|
||||
template<typename Rep, Reference R>
|
||||
requires detail::OffsetUnit<decltype(get_unit(R{}))> &&
|
||||
RepresentationOf<std::remove_cvref_t<Rep>, get_quantity_spec(R{}).character>
|
||||
[[noreturn]] constexpr auto operator*(Rep&&, R)
|
||||
template<typename FwdRep, Reference R,
|
||||
RepresentationOf<get_quantity_spec(R{}).character> Rep = std::remove_cvref_t<FwdRep>>
|
||||
requires detail::OffsetUnit<decltype(get_unit(R{}))>
|
||||
[[noreturn]] constexpr auto operator*(FwdRep&&, R)
|
||||
{
|
||||
static_assert(!detail::OffsetUnit<decltype(get_unit(R{}))>,
|
||||
"References using offset units (e.g., temperatures) may be constructed only with the `delta` or "
|
||||
"`absolute` helpers");
|
||||
}
|
||||
|
||||
template<typename Rep, Reference R>
|
||||
requires detail::OffsetUnit<decltype(get_unit(R{}))> &&
|
||||
RepresentationOf<std::remove_cvref_t<Rep>, get_quantity_spec(R{}).character>
|
||||
[[noreturn]] constexpr auto operator/(Rep&&, R)
|
||||
template<typename FwdRep, Reference R,
|
||||
RepresentationOf<get_quantity_spec(R{}).character> Rep = std::remove_cvref_t<FwdRep>>
|
||||
requires detail::OffsetUnit<decltype(get_unit(R{}))>
|
||||
[[noreturn]] constexpr auto operator/(FwdRep&&, R)
|
||||
{
|
||||
static_assert(!detail::OffsetUnit<decltype(get_unit(R{}))>,
|
||||
"References using offset units (e.g., temperatures) may be constructed only with the `delta` or "
|
||||
@@ -246,20 +246,16 @@ constexpr auto operator/(R, Rep&&)
|
||||
= delete;
|
||||
#endif
|
||||
|
||||
template<typename Q, Reference R>
|
||||
requires Quantity<std::remove_cvref_t<Q>>
|
||||
[[nodiscard]] constexpr Quantity auto operator*(Q&& q, R)
|
||||
template<typename FwdQ, Reference R, Quantity Q = std::remove_cvref_t<FwdQ>>
|
||||
[[nodiscard]] constexpr Quantity auto operator*(FwdQ&& q, R)
|
||||
{
|
||||
return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_,
|
||||
std::remove_cvref_t<Q>::reference * R{}};
|
||||
return quantity{std::forward<FwdQ>(q).numerical_value_is_an_implementation_detail_, Q::reference * R{}};
|
||||
}
|
||||
|
||||
template<typename Q, Reference R>
|
||||
requires Quantity<std::remove_cvref_t<Q>>
|
||||
[[nodiscard]] constexpr Quantity auto operator/(Q&& q, R)
|
||||
template<typename FwdQ, Reference R, Quantity Q = std::remove_cvref_t<FwdQ>>
|
||||
[[nodiscard]] constexpr Quantity auto operator/(FwdQ&& q, R)
|
||||
{
|
||||
return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_,
|
||||
std::remove_cvref_t<Q>::reference / R{}};
|
||||
return quantity{std::forward<FwdQ>(q).numerical_value_is_an_implementation_detail_, Q::reference / R{}};
|
||||
}
|
||||
|
||||
template<Reference R, typename Q>
|
||||
|
@@ -79,10 +79,14 @@ concept Scalable =
|
||||
CastableNumber<T> || (requires { typename wrapped_type_t<T>; } && CastableNumber<wrapped_type_t<T>> &&
|
||||
ScalableNumber<T, std::common_type_t<wrapped_type_t<T>, std::intmax_t>>);
|
||||
|
||||
template<typename T>
|
||||
concept WeaklyRegular = std::copyable<T> && std::equality_comparable<T>;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
MP_UNITS_EXPORT template<typename T>
|
||||
concept Representation = (is_scalar<T> || is_vector<T> || is_tensor<T>)&&std::regular<T> && detail::Scalable<T>;
|
||||
concept Representation =
|
||||
(is_scalar<T> || is_vector<T> || is_tensor<T>)&&detail::WeaklyRegular<T> && detail::Scalable<T>;
|
||||
|
||||
MP_UNITS_EXPORT template<typename T, quantity_character Ch>
|
||||
concept RepresentationOf = Representation<T> && ((Ch == quantity_character::scalar && is_scalar<T>) ||
|
||||
|
@@ -64,7 +64,7 @@ template<Magnitude auto M, Unit U>
|
||||
struct scaled_unit_impl;
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_specialization_of_scaled_unit = false;
|
||||
constexpr bool is_specialization_of_scaled_unit = false;
|
||||
|
||||
template<DerivedUnitExpr... Expr>
|
||||
struct derived_unit_impl;
|
||||
@@ -241,7 +241,7 @@ struct scaled_unit final : detail::scaled_unit_impl<M, U> {};
|
||||
namespace detail {
|
||||
|
||||
template<auto M, Unit U>
|
||||
inline constexpr bool is_specialization_of_scaled_unit<scaled_unit<M, U>> = true;
|
||||
constexpr bool is_specialization_of_scaled_unit<scaled_unit<M, U>> = true;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -386,7 +386,7 @@ struct named_unit<Symbol, U, QS, PO> : decltype(U)::_base_type_ {
|
||||
* struct kilo_ : prefixed_unit<"k", mag_power<10, 3>, U> {};
|
||||
*
|
||||
* template<PrefixableUnit auto U>
|
||||
* inline constexpr kilo_<U> kilo;
|
||||
* constexpr kilo_<U> kilo;
|
||||
*
|
||||
* inline constexpr auto kilogram = si::kilo<gram>;
|
||||
* @endcode
|
||||
@@ -534,10 +534,10 @@ template<Unit T, typename... Expr>
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_specialization_of_derived_unit = false;
|
||||
constexpr bool is_specialization_of_derived_unit = false;
|
||||
|
||||
template<typename... Expr>
|
||||
inline constexpr bool is_specialization_of_derived_unit<derived_unit<Expr...>> = true;
|
||||
constexpr bool is_specialization_of_derived_unit<derived_unit<Expr...>> = true;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -675,14 +675,14 @@ template<Unit U1, Unit U2>
|
||||
* be provided.
|
||||
*/
|
||||
template<Unit auto U>
|
||||
inline constexpr bool space_before_unit_symbol = true;
|
||||
constexpr bool space_before_unit_symbol = true;
|
||||
|
||||
template<>
|
||||
inline constexpr bool space_before_unit_symbol<one> = false;
|
||||
MP_UNITS_INLINE constexpr bool space_before_unit_symbol<one> = false;
|
||||
template<>
|
||||
inline constexpr bool space_before_unit_symbol<percent> = false;
|
||||
MP_UNITS_INLINE constexpr bool space_before_unit_symbol<percent> = false;
|
||||
template<>
|
||||
inline constexpr bool space_before_unit_symbol<per_mille> = false;
|
||||
MP_UNITS_INLINE constexpr bool space_before_unit_symbol<per_mille> = false;
|
||||
|
||||
// get_unit_symbol
|
||||
|
||||
|
@@ -59,7 +59,7 @@ template<symbol_text Symbol, auto... Args>
|
||||
void to_base_specialization_of_named_unit(const volatile named_unit<Symbol, Args...>*);
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_derived_from_specialization_of_named_unit =
|
||||
constexpr bool is_derived_from_specialization_of_named_unit =
|
||||
requires(T* t) { to_base_specialization_of_named_unit(t); };
|
||||
|
||||
} // namespace detail
|
||||
@@ -73,14 +73,13 @@ concept PrefixableUnit = Unit<T> && detail::is_derived_from_specialization_of_na
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_power_of_unit =
|
||||
requires { requires is_specialization_of_power<T> && Unit<typename T::factor>; };
|
||||
constexpr bool is_power_of_unit = requires { requires is_specialization_of_power<T> && Unit<typename T::factor>; };
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_per_of_units = false;
|
||||
constexpr bool is_per_of_units = false;
|
||||
|
||||
template<typename... Ts>
|
||||
inline constexpr bool is_per_of_units<per<Ts...>> = (... && (Unit<Ts> || is_power_of_unit<Ts>));
|
||||
constexpr bool is_per_of_units<per<Ts...>> = (... && (Unit<Ts> || is_power_of_unit<Ts>));
|
||||
|
||||
template<typename T>
|
||||
concept DerivedUnitExpr = Unit<T> || detail::is_power_of_unit<T> || detail::is_per_of_units<T>;
|
||||
|
@@ -44,13 +44,12 @@ namespace mp_units {
|
||||
*
|
||||
* @tparam ToU a unit to use for a target quantity
|
||||
*/
|
||||
template<Unit auto ToU, typename Q>
|
||||
requires Quantity<std::remove_cvref_t<Q>> && (convertible(std::remove_reference_t<Q>::reference, ToU))
|
||||
[[nodiscard]] constexpr Quantity auto value_cast(Q&& q)
|
||||
template<Unit auto ToU, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>>
|
||||
requires(convertible(Q::reference, ToU))
|
||||
[[nodiscard]] constexpr Quantity auto value_cast(FwdQ&& q)
|
||||
{
|
||||
using q_type = std::remove_reference_t<Q>;
|
||||
return detail::sudo_cast<quantity<detail::make_reference(q_type::quantity_spec, ToU), typename q_type::rep>>(
|
||||
std::forward<Q>(q));
|
||||
return detail::sudo_cast<quantity<detail::make_reference(Q::quantity_spec, ToU), typename Q::rep>>(
|
||||
std::forward<FwdQ>(q));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,13 +62,11 @@ template<Unit auto ToU, typename Q>
|
||||
*
|
||||
* @tparam ToRep a representation type to use for a target quantity
|
||||
*/
|
||||
template<Representation ToRep, typename Q>
|
||||
requires Quantity<std::remove_cvref_t<Q>> &&
|
||||
RepresentationOf<ToRep, std::remove_reference_t<Q>::quantity_spec.character> &&
|
||||
std::constructible_from<ToRep, typename std::remove_reference_t<Q>::rep>
|
||||
[[nodiscard]] constexpr quantity<std::remove_reference_t<Q>::reference, ToRep> value_cast(Q&& q)
|
||||
template<Representation ToRep, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>>
|
||||
requires RepresentationOf<ToRep, Q::quantity_spec.character> && std::constructible_from<ToRep, typename Q::rep>
|
||||
[[nodiscard]] constexpr quantity<Q::reference, ToRep> value_cast(FwdQ&& q)
|
||||
{
|
||||
return detail::sudo_cast<quantity<std::remove_reference_t<Q>::reference, ToRep>>(std::forward<Q>(q));
|
||||
return detail::sudo_cast<quantity<Q::reference, ToRep>>(std::forward<FwdQ>(q));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,14 +80,12 @@ template<Representation ToRep, typename Q>
|
||||
* @tparam ToU a unit to use for the target quantity
|
||||
* @tparam ToRep a representation type to use for the target quantity
|
||||
*/
|
||||
template<Unit auto ToU, Representation ToRep, typename Q>
|
||||
requires Quantity<std::remove_cvref_t<Q>> && (convertible(std::remove_reference_t<Q>::reference, ToU)) &&
|
||||
RepresentationOf<ToRep, std::remove_reference_t<Q>::quantity_spec.character> &&
|
||||
std::constructible_from<ToRep, typename std::remove_reference_t<Q>::rep>
|
||||
[[nodiscard]] constexpr Quantity auto value_cast(Q&& q)
|
||||
template<Unit auto ToU, Representation ToRep, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>>
|
||||
requires(convertible(Q::reference, ToU)) && RepresentationOf<ToRep, Q::quantity_spec.character> &&
|
||||
std::constructible_from<ToRep, typename Q::rep>
|
||||
[[nodiscard]] constexpr Quantity auto value_cast(FwdQ&& q)
|
||||
{
|
||||
using q_type = std::remove_reference_t<Q>;
|
||||
return detail::sudo_cast<quantity<detail::make_reference(q_type::quantity_spec, ToU), ToRep>>(std::forward<Q>(q));
|
||||
return detail::sudo_cast<quantity<detail::make_reference(Q::quantity_spec, ToU), ToRep>>(std::forward<FwdQ>(q));
|
||||
}
|
||||
|
||||
|
||||
@@ -108,13 +103,12 @@ template<Unit auto ToU, Representation ToRep, typename Q>
|
||||
*
|
||||
* @tparam ToQ a target quantity type to which to cast the representation
|
||||
*/
|
||||
template<Quantity ToQ, typename Q>
|
||||
requires Quantity<std::remove_cvref_t<Q>> && (convertible(std::remove_reference_t<Q>::reference, ToQ::unit)) &&
|
||||
(ToQ::quantity_spec == std::remove_reference_t<Q>::quantity_spec) &&
|
||||
std::constructible_from<typename ToQ::rep, typename std::remove_reference_t<Q>::rep>
|
||||
[[nodiscard]] constexpr Quantity auto value_cast(Q&& q)
|
||||
template<Quantity ToQ, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>>
|
||||
requires(convertible(Q::reference, ToQ::unit)) &&
|
||||
(ToQ::quantity_spec == Q::quantity_spec) && std::constructible_from<typename ToQ::rep, typename Q::rep>
|
||||
[[nodiscard]] constexpr Quantity auto value_cast(FwdQ&& q)
|
||||
{
|
||||
return detail::sudo_cast<ToQ>(std::forward<Q>(q));
|
||||
return detail::sudo_cast<ToQ>(std::forward<FwdQ>(q));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,12 +121,12 @@ template<Quantity ToQ, typename Q>
|
||||
*
|
||||
* @tparam ToU a unit to use for a target quantity point
|
||||
*/
|
||||
template<Unit auto ToU, typename QP>
|
||||
requires QuantityPoint<std::remove_cvref_t<QP>> && (convertible(std::remove_reference_t<QP>::reference, ToU))
|
||||
[[nodiscard]] constexpr QuantityPoint auto value_cast(QP&& qp)
|
||||
template<Unit auto ToU, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<FwdQP>>
|
||||
requires(convertible(QP::reference, ToU))
|
||||
[[nodiscard]] constexpr QuantityPoint auto value_cast(FwdQP&& qp)
|
||||
{
|
||||
return quantity_point{value_cast<ToU>(std::forward<QP>(qp).quantity_from_origin_is_an_implementation_detail_),
|
||||
std::remove_reference_t<QP>::point_origin};
|
||||
return quantity_point{value_cast<ToU>(std::forward<FwdQP>(qp).quantity_from_origin_is_an_implementation_detail_),
|
||||
QP::point_origin};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -145,16 +139,12 @@ template<Unit auto ToU, typename QP>
|
||||
*
|
||||
* @tparam ToRep a representation type to use for a target quantity point
|
||||
*/
|
||||
template<Representation ToRep, typename QP>
|
||||
requires QuantityPoint<std::remove_cvref_t<QP>> &&
|
||||
RepresentationOf<ToRep, std::remove_reference_t<QP>::quantity_spec.character> &&
|
||||
std::constructible_from<ToRep, typename std::remove_reference_t<QP>::rep>
|
||||
[[nodiscard]] constexpr quantity_point<std::remove_reference_t<QP>::reference,
|
||||
std::remove_reference_t<QP>::point_origin, ToRep>
|
||||
value_cast(QP&& qp)
|
||||
template<Representation ToRep, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<FwdQP>>
|
||||
requires RepresentationOf<ToRep, QP::quantity_spec.character> && std::constructible_from<ToRep, typename QP::rep>
|
||||
[[nodiscard]] constexpr quantity_point<QP::reference, QP::point_origin, ToRep> value_cast(FwdQP&& qp)
|
||||
{
|
||||
return {value_cast<ToRep>(std::forward<QP>(qp).quantity_from_origin_is_an_implementation_detail_),
|
||||
std::remove_reference_t<QP>::point_origin};
|
||||
return {value_cast<ToRep>(std::forward<FwdQP>(qp).quantity_from_origin_is_an_implementation_detail_),
|
||||
QP::point_origin};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -168,14 +158,14 @@ value_cast(QP&& qp)
|
||||
* @tparam ToU a unit to use for the target quantity
|
||||
* @tparam ToRep a representation type to use for the target quantity
|
||||
*/
|
||||
template<Unit auto ToU, Representation ToRep, typename QP>
|
||||
requires QuantityPoint<std::remove_cvref_t<QP>> && (convertible(std::remove_reference_t<QP>::reference, ToU)) &&
|
||||
RepresentationOf<ToRep, std::remove_reference_t<QP>::quantity_spec.character> &&
|
||||
std::constructible_from<ToRep, typename std::remove_reference_t<QP>::rep>
|
||||
[[nodiscard]] constexpr QuantityPoint auto value_cast(QP&& qp)
|
||||
template<Unit auto ToU, Representation ToRep, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<FwdQP>>
|
||||
requires(convertible(QP::reference, ToU)) && RepresentationOf<ToRep, QP::quantity_spec.character> &&
|
||||
std::constructible_from<ToRep, typename QP::rep>
|
||||
[[nodiscard]] constexpr QuantityPoint auto value_cast(FwdQP&& qp)
|
||||
{
|
||||
return quantity_point{value_cast<ToU, ToRep>(std::forward<QP>(qp).quantity_from_origin_is_an_implementation_detail_),
|
||||
std::remove_reference_t<QP>::point_origin};
|
||||
return quantity_point{
|
||||
value_cast<ToU, ToRep>(std::forward<FwdQP>(qp).quantity_from_origin_is_an_implementation_detail_),
|
||||
QP::point_origin};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -194,14 +184,13 @@ template<Unit auto ToU, Representation ToRep, typename QP>
|
||||
*
|
||||
* @tparam ToQ a target quantity type to which to cast the representation of the point
|
||||
*/
|
||||
template<Quantity ToQ, typename QP>
|
||||
requires QuantityPoint<std::remove_cvref_t<QP>> && (convertible(std::remove_reference_t<QP>::reference, ToQ::unit)) &&
|
||||
(ToQ::quantity_spec == std::remove_reference_t<QP>::quantity_spec) &&
|
||||
std::constructible_from<typename ToQ::rep, typename std::remove_reference_t<QP>::rep>
|
||||
[[nodiscard]] constexpr QuantityPoint auto value_cast(QP&& qp)
|
||||
template<Quantity ToQ, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<FwdQP>>
|
||||
requires(convertible(QP::reference, ToQ::unit)) &&
|
||||
(ToQ::quantity_spec == QP::quantity_spec) && std::constructible_from<typename ToQ::rep, typename QP::rep>
|
||||
[[nodiscard]] constexpr QuantityPoint auto value_cast(FwdQP&& qp)
|
||||
{
|
||||
return quantity_point{value_cast<ToQ>(std::forward<QP>(qp).quantity_from_origin_is_an_implementation_detail_),
|
||||
std::remove_reference_t<QP>::point_origin};
|
||||
return quantity_point{value_cast<ToQ>(std::forward<FwdQP>(qp).quantity_from_origin_is_an_implementation_detail_),
|
||||
QP::point_origin};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -232,16 +221,13 @@ template<Quantity ToQ, typename QP>
|
||||
*
|
||||
* @tparam ToQP a target quantity point type to which to cast the representation of the point
|
||||
*/
|
||||
template<QuantityPoint ToQP, typename QP>
|
||||
requires QuantityPoint<std::remove_cvref_t<QP>> &&
|
||||
(convertible(std::remove_reference_t<QP>::reference, ToQP::unit)) &&
|
||||
(ToQP::quantity_spec == std::remove_reference_t<QP>::quantity_spec) &&
|
||||
(detail::same_absolute_point_origins(ToQP::point_origin, std::remove_reference_t<QP>::point_origin)) &&
|
||||
std::constructible_from<typename ToQP::rep, typename std::remove_reference_t<QP>::rep>
|
||||
[[nodiscard]] constexpr QuantityPoint auto value_cast(QP&& qp)
|
||||
template<QuantityPoint ToQP, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<FwdQP>>
|
||||
requires(convertible(QP::reference, ToQP::unit)) && (ToQP::quantity_spec == QP::quantity_spec) &&
|
||||
(detail::same_absolute_point_origins(ToQP::point_origin, QP::point_origin)) &&
|
||||
std::constructible_from<typename ToQP::rep, typename QP::rep>
|
||||
[[nodiscard]] constexpr QuantityPoint auto value_cast(FwdQP&& qp)
|
||||
{
|
||||
return detail::sudo_cast<ToQP>(std::forward<QP>(qp));
|
||||
return detail::sudo_cast<ToQP>(std::forward<FwdQP>(qp));
|
||||
}
|
||||
|
||||
|
||||
} // namespace mp_units
|
||||
|
@@ -62,8 +62,8 @@ inline constexpr auto deg2 = square(degree);
|
||||
} // namespace angular
|
||||
|
||||
template<>
|
||||
inline constexpr bool space_before_unit_symbol<angular::degree> = false;
|
||||
MP_UNITS_INLINE constexpr bool space_before_unit_symbol<angular::degree> = false;
|
||||
template<>
|
||||
inline constexpr bool space_before_unit_symbol<angular::gradian> = false;
|
||||
MP_UNITS_INLINE constexpr bool space_before_unit_symbol<angular::gradian> = false;
|
||||
|
||||
} // namespace mp_units
|
||||
|
@@ -36,7 +36,7 @@ MP_UNITS_EXPORT
|
||||
namespace mp_units {
|
||||
|
||||
template<>
|
||||
inline constexpr std::optional<std::intmax_t> known_first_factor<334'524'384'739> = 334'524'384'739;
|
||||
constexpr std::optional<std::intmax_t> known_first_factor<334'524'384'739> = 334'524'384'739;
|
||||
|
||||
namespace hep {
|
||||
|
||||
|
@@ -42,14 +42,14 @@ template<PrefixableUnit U> struct yobi_ final : prefixed_unit<"Yi", mag_power<2,
|
||||
|
||||
MP_UNITS_EXPORT_BEGIN
|
||||
|
||||
template<PrefixableUnit auto U> inline constexpr kibi_<MP_UNITS_REMOVE_CONST(decltype(U))> kibi;
|
||||
template<PrefixableUnit auto U> inline constexpr mebi_<MP_UNITS_REMOVE_CONST(decltype(U))> mebi;
|
||||
template<PrefixableUnit auto U> inline constexpr gibi_<MP_UNITS_REMOVE_CONST(decltype(U))> gibi;
|
||||
template<PrefixableUnit auto U> inline constexpr tebi_<MP_UNITS_REMOVE_CONST(decltype(U))> tebi;
|
||||
template<PrefixableUnit auto U> inline constexpr pebi_<MP_UNITS_REMOVE_CONST(decltype(U))> pebi;
|
||||
template<PrefixableUnit auto U> inline constexpr exbi_<MP_UNITS_REMOVE_CONST(decltype(U))> exbi;
|
||||
template<PrefixableUnit auto U> inline constexpr zebi_<MP_UNITS_REMOVE_CONST(decltype(U))> zebi;
|
||||
template<PrefixableUnit auto U> inline constexpr yobi_<MP_UNITS_REMOVE_CONST(decltype(U))> yobi;
|
||||
template<PrefixableUnit auto U> constexpr kibi_<MP_UNITS_REMOVE_CONST(decltype(U))> kibi;
|
||||
template<PrefixableUnit auto U> constexpr mebi_<MP_UNITS_REMOVE_CONST(decltype(U))> mebi;
|
||||
template<PrefixableUnit auto U> constexpr gibi_<MP_UNITS_REMOVE_CONST(decltype(U))> gibi;
|
||||
template<PrefixableUnit auto U> constexpr tebi_<MP_UNITS_REMOVE_CONST(decltype(U))> tebi;
|
||||
template<PrefixableUnit auto U> constexpr pebi_<MP_UNITS_REMOVE_CONST(decltype(U))> pebi;
|
||||
template<PrefixableUnit auto U> constexpr exbi_<MP_UNITS_REMOVE_CONST(decltype(U))> exbi;
|
||||
template<PrefixableUnit auto U> constexpr zebi_<MP_UNITS_REMOVE_CONST(decltype(U))> zebi;
|
||||
template<PrefixableUnit auto U> constexpr yobi_<MP_UNITS_REMOVE_CONST(decltype(U))> yobi;
|
||||
// clang-format on
|
||||
|
||||
MP_UNITS_EXPORT_END
|
||||
|
@@ -93,7 +93,7 @@ struct chrono_point_origin_ final : absolute_point_origin<isq::time> {
|
||||
using clock = C;
|
||||
};
|
||||
MP_UNITS_EXPORT template<typename C>
|
||||
inline constexpr chrono_point_origin_<C> chrono_point_origin;
|
||||
constexpr chrono_point_origin_<C> chrono_point_origin;
|
||||
|
||||
MP_UNITS_EXPORT_BEGIN
|
||||
|
||||
|
@@ -58,30 +58,30 @@ template<PrefixableUnit U> struct quetta_ final : prefixed_unit<"Q", mag_power<1
|
||||
|
||||
MP_UNITS_EXPORT_BEGIN
|
||||
|
||||
template<PrefixableUnit auto U> inline constexpr quecto_<MP_UNITS_REMOVE_CONST(decltype(U))> quecto;
|
||||
template<PrefixableUnit auto U> inline constexpr ronto_<MP_UNITS_REMOVE_CONST(decltype(U))> ronto;
|
||||
template<PrefixableUnit auto U> inline constexpr yocto_<MP_UNITS_REMOVE_CONST(decltype(U))> yocto;
|
||||
template<PrefixableUnit auto U> inline constexpr zepto_<MP_UNITS_REMOVE_CONST(decltype(U))> zepto;
|
||||
template<PrefixableUnit auto U> inline constexpr atto_<MP_UNITS_REMOVE_CONST(decltype(U))> atto;
|
||||
template<PrefixableUnit auto U> inline constexpr femto_<MP_UNITS_REMOVE_CONST(decltype(U))> femto;
|
||||
template<PrefixableUnit auto U> inline constexpr pico_<MP_UNITS_REMOVE_CONST(decltype(U))> pico;
|
||||
template<PrefixableUnit auto U> inline constexpr nano_<MP_UNITS_REMOVE_CONST(decltype(U))> nano;
|
||||
template<PrefixableUnit auto U> inline constexpr micro_<MP_UNITS_REMOVE_CONST(decltype(U))> micro;
|
||||
template<PrefixableUnit auto U> inline constexpr milli_<MP_UNITS_REMOVE_CONST(decltype(U))> milli;
|
||||
template<PrefixableUnit auto U> inline constexpr centi_<MP_UNITS_REMOVE_CONST(decltype(U))> centi;
|
||||
template<PrefixableUnit auto U> inline constexpr deci_<MP_UNITS_REMOVE_CONST(decltype(U))> deci;
|
||||
template<PrefixableUnit auto U> inline constexpr deca_<MP_UNITS_REMOVE_CONST(decltype(U))> deca;
|
||||
template<PrefixableUnit auto U> inline constexpr hecto_<MP_UNITS_REMOVE_CONST(decltype(U))> hecto;
|
||||
template<PrefixableUnit auto U> inline constexpr kilo_<MP_UNITS_REMOVE_CONST(decltype(U))> kilo;
|
||||
template<PrefixableUnit auto U> inline constexpr mega_<MP_UNITS_REMOVE_CONST(decltype(U))> mega;
|
||||
template<PrefixableUnit auto U> inline constexpr giga_<MP_UNITS_REMOVE_CONST(decltype(U))> giga;
|
||||
template<PrefixableUnit auto U> inline constexpr tera_<MP_UNITS_REMOVE_CONST(decltype(U))> tera;
|
||||
template<PrefixableUnit auto U> inline constexpr peta_<MP_UNITS_REMOVE_CONST(decltype(U))> peta;
|
||||
template<PrefixableUnit auto U> inline constexpr exa_<MP_UNITS_REMOVE_CONST(decltype(U))> exa;
|
||||
template<PrefixableUnit auto U> inline constexpr zetta_<MP_UNITS_REMOVE_CONST(decltype(U))> zetta;
|
||||
template<PrefixableUnit auto U> inline constexpr yotta_<MP_UNITS_REMOVE_CONST(decltype(U))> yotta;
|
||||
template<PrefixableUnit auto U> inline constexpr ronna_<MP_UNITS_REMOVE_CONST(decltype(U))> ronna;
|
||||
template<PrefixableUnit auto U> inline constexpr quetta_<MP_UNITS_REMOVE_CONST(decltype(U))> quetta;
|
||||
template<PrefixableUnit auto U> constexpr quecto_<MP_UNITS_REMOVE_CONST(decltype(U))> quecto;
|
||||
template<PrefixableUnit auto U> constexpr ronto_<MP_UNITS_REMOVE_CONST(decltype(U))> ronto;
|
||||
template<PrefixableUnit auto U> constexpr yocto_<MP_UNITS_REMOVE_CONST(decltype(U))> yocto;
|
||||
template<PrefixableUnit auto U> constexpr zepto_<MP_UNITS_REMOVE_CONST(decltype(U))> zepto;
|
||||
template<PrefixableUnit auto U> constexpr atto_<MP_UNITS_REMOVE_CONST(decltype(U))> atto;
|
||||
template<PrefixableUnit auto U> constexpr femto_<MP_UNITS_REMOVE_CONST(decltype(U))> femto;
|
||||
template<PrefixableUnit auto U> constexpr pico_<MP_UNITS_REMOVE_CONST(decltype(U))> pico;
|
||||
template<PrefixableUnit auto U> constexpr nano_<MP_UNITS_REMOVE_CONST(decltype(U))> nano;
|
||||
template<PrefixableUnit auto U> constexpr micro_<MP_UNITS_REMOVE_CONST(decltype(U))> micro;
|
||||
template<PrefixableUnit auto U> constexpr milli_<MP_UNITS_REMOVE_CONST(decltype(U))> milli;
|
||||
template<PrefixableUnit auto U> constexpr centi_<MP_UNITS_REMOVE_CONST(decltype(U))> centi;
|
||||
template<PrefixableUnit auto U> constexpr deci_<MP_UNITS_REMOVE_CONST(decltype(U))> deci;
|
||||
template<PrefixableUnit auto U> constexpr deca_<MP_UNITS_REMOVE_CONST(decltype(U))> deca;
|
||||
template<PrefixableUnit auto U> constexpr hecto_<MP_UNITS_REMOVE_CONST(decltype(U))> hecto;
|
||||
template<PrefixableUnit auto U> constexpr kilo_<MP_UNITS_REMOVE_CONST(decltype(U))> kilo;
|
||||
template<PrefixableUnit auto U> constexpr mega_<MP_UNITS_REMOVE_CONST(decltype(U))> mega;
|
||||
template<PrefixableUnit auto U> constexpr giga_<MP_UNITS_REMOVE_CONST(decltype(U))> giga;
|
||||
template<PrefixableUnit auto U> constexpr tera_<MP_UNITS_REMOVE_CONST(decltype(U))> tera;
|
||||
template<PrefixableUnit auto U> constexpr peta_<MP_UNITS_REMOVE_CONST(decltype(U))> peta;
|
||||
template<PrefixableUnit auto U> constexpr exa_<MP_UNITS_REMOVE_CONST(decltype(U))> exa;
|
||||
template<PrefixableUnit auto U> constexpr zetta_<MP_UNITS_REMOVE_CONST(decltype(U))> zetta;
|
||||
template<PrefixableUnit auto U> constexpr yotta_<MP_UNITS_REMOVE_CONST(decltype(U))> yotta;
|
||||
template<PrefixableUnit auto U> constexpr ronna_<MP_UNITS_REMOVE_CONST(decltype(U))> ronna;
|
||||
template<PrefixableUnit auto U> constexpr quetta_<MP_UNITS_REMOVE_CONST(decltype(U))> quetta;
|
||||
// clang-format on
|
||||
|
||||
MP_UNITS_EXPORT_END
|
||||
|
@@ -126,10 +126,10 @@ using namespace non_si;
|
||||
} // namespace si
|
||||
|
||||
template<>
|
||||
inline constexpr bool space_before_unit_symbol<non_si::degree> = false;
|
||||
MP_UNITS_INLINE constexpr bool space_before_unit_symbol<non_si::degree> = false;
|
||||
template<>
|
||||
inline constexpr bool space_before_unit_symbol<non_si::arcminute> = false;
|
||||
MP_UNITS_INLINE constexpr bool space_before_unit_symbol<non_si::arcminute> = false;
|
||||
template<>
|
||||
inline constexpr bool space_before_unit_symbol<non_si::arcsecond> = false;
|
||||
MP_UNITS_INLINE constexpr bool space_before_unit_symbol<non_si::arcsecond> = false;
|
||||
|
||||
} // namespace mp_units
|
||||
|
@@ -50,7 +50,7 @@ import mp_units;
|
||||
|
||||
template<class T>
|
||||
requires mp_units::is_scalar<T>
|
||||
inline constexpr bool mp_units::is_vector<T> = true;
|
||||
constexpr bool mp_units::is_vector<T> = true;
|
||||
|
||||
using namespace mp_units;
|
||||
using namespace mp_units::si::unit_symbols;
|
||||
|
@@ -44,10 +44,10 @@ template<typename Rep = double>
|
||||
using vector = STD_LA::fixed_size_column_vector<Rep, 3>;
|
||||
|
||||
template<class Rep>
|
||||
inline constexpr bool mp_units::treat_as_floating_point<vector<Rep>> = mp_units::treat_as_floating_point<Rep>;
|
||||
constexpr bool mp_units::treat_as_floating_point<vector<Rep>> = mp_units::treat_as_floating_point<Rep>;
|
||||
|
||||
template<typename Rep>
|
||||
inline constexpr bool mp_units::is_vector<vector<Rep>> = true;
|
||||
constexpr bool mp_units::is_vector<vector<Rep>> = true;
|
||||
|
||||
template<typename Rep>
|
||||
std::ostream& operator<<(std::ostream& os, const vector<Rep>& v)
|
||||
@@ -301,7 +301,7 @@ TEST_CASE("vector quantity", "[la]")
|
||||
|
||||
template<class T>
|
||||
requires mp_units::is_scalar<T>
|
||||
inline constexpr bool mp_units::is_vector<T> = true;
|
||||
constexpr bool mp_units::is_vector<T> = true;
|
||||
|
||||
TEST_CASE("vector of quantities", "[la]")
|
||||
{
|
||||
|
@@ -73,3 +73,9 @@ TEST_CASE("Issue 474 is fixed", "[conversion][radical]")
|
||||
REQUIRE(within_4_ulps(sqrt(val_issue_474).numerical_value_in(m / s),
|
||||
sqrt(val_issue_474.numerical_value_in(m * m / s / s))));
|
||||
}
|
||||
|
||||
TEST_CASE("Volatile representation type", "[volatile]")
|
||||
{
|
||||
volatile std::int16_t vint = 123;
|
||||
REQUIRE(quantity(vint * m).numerical_value_in(m) == 123);
|
||||
}
|
||||
|
@@ -28,7 +28,7 @@
|
||||
|
||||
template<class T>
|
||||
requires mp_units::is_scalar<T>
|
||||
inline constexpr bool mp_units::is_vector<T> = true;
|
||||
constexpr bool mp_units::is_vector<T> = true;
|
||||
|
||||
namespace {
|
||||
|
||||
|
@@ -37,7 +37,7 @@ import std;
|
||||
|
||||
#if MP_UNITS_HOSTED
|
||||
template<typename T>
|
||||
inline constexpr bool mp_units::is_scalar<std::complex<T>> = true;
|
||||
constexpr bool mp_units::is_scalar<std::complex<T>> = true;
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
@@ -61,7 +61,7 @@ public:
|
||||
} // namespace
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool mp_units::is_scalar<min_impl<T>> = true;
|
||||
constexpr bool mp_units::is_scalar<min_impl<T>> = true;
|
||||
|
||||
template<typename T, typename U>
|
||||
struct std::common_type<min_impl<T>, min_impl<U>> : std::type_identity<min_impl<std::common_type_t<T, U>>> {};
|
||||
|
@@ -26,7 +26,7 @@
|
||||
|
||||
template<class T>
|
||||
requires mp_units::is_scalar<T>
|
||||
inline constexpr bool mp_units::is_vector<T> = true;
|
||||
constexpr bool mp_units::is_vector<T> = true;
|
||||
|
||||
namespace {
|
||||
|
||||
|
@@ -28,7 +28,7 @@
|
||||
|
||||
template<class T>
|
||||
requires mp_units::is_scalar<T>
|
||||
inline constexpr bool mp_units::is_vector<T> = true;
|
||||
constexpr bool mp_units::is_vector<T> = true;
|
||||
|
||||
namespace {
|
||||
|
||||
|
@@ -32,7 +32,7 @@ using namespace units;
|
||||
using namespace units::detail;
|
||||
|
||||
template<>
|
||||
inline constexpr std::optional<std::intmax_t> units::known_first_factor<9223372036854775783> = 9223372036854775783;
|
||||
constexpr std::optional<std::intmax_t> units::known_first_factor<9223372036854775783> = 9223372036854775783;
|
||||
|
||||
namespace {
|
||||
|
||||
|
@@ -24,7 +24,7 @@
|
||||
|
||||
template<class T>
|
||||
requires mp_units::is_scalar<T>
|
||||
inline constexpr bool mp_units::is_vector<T> = true;
|
||||
constexpr bool mp_units::is_vector<T> = true;
|
||||
|
||||
namespace {
|
||||
|
||||
|
@@ -111,12 +111,12 @@ static_assert(ground_level != other_ground_level);
|
||||
template<auto QS>
|
||||
struct absolute_po_ final : absolute_point_origin<QS> {};
|
||||
template<auto QS>
|
||||
inline constexpr absolute_po_<QS> absolute_po;
|
||||
constexpr absolute_po_<QS> absolute_po;
|
||||
|
||||
template<auto QP>
|
||||
struct relative_po_ final : relative_point_origin<QP> {};
|
||||
template<auto QP>
|
||||
inline constexpr relative_po_<QP> relative_po;
|
||||
constexpr relative_po_<QP> relative_po;
|
||||
|
||||
static_assert(relative_po<absolute_po<isq::length> + isq::height(42 * m)>.quantity_spec == isq::height);
|
||||
static_assert(relative_po<absolute_po<kind_of<isq::length>> + isq::height(42 * m)>.quantity_spec == isq::height);
|
||||
|
@@ -41,7 +41,7 @@ import std;
|
||||
#endif
|
||||
|
||||
template<>
|
||||
inline constexpr bool mp_units::is_vector<int> = true;
|
||||
constexpr bool mp_units::is_vector<int> = true;
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -115,6 +115,10 @@ static_assert(quantity<isq::length[m]>::unit == si::metre);
|
||||
static_assert(is_same_v<quantity<isq::length[m]>::rep, double>);
|
||||
static_assert(is_same_v<quantity<isq::length[m], int>::rep, int>);
|
||||
|
||||
[[maybe_unused]] volatile std::int16_t vint = 123;
|
||||
static_assert(is_same_v<decltype(quantity(vint * m))::rep, std::int16_t>);
|
||||
static_assert(is_same_v<decltype(quantity(vint, m))::rep, std::int16_t>);
|
||||
|
||||
|
||||
////////////////////////////
|
||||
// static member functions
|
||||
@@ -260,6 +264,9 @@ static_assert(quantity<isq::length[km], int>(2 * km).force_in(km).numerical_valu
|
||||
static_assert(quantity<isq::length[km], int>(2 * km).force_in(m).numerical_value_in(m) == 2000);
|
||||
static_assert(quantity<isq::length[m], int>(2000 * m).force_in(km).numerical_value_in(km) == 2);
|
||||
|
||||
static_assert((15. * m).in(nm).numerical_value_in(m) == 15.);
|
||||
static_assert((15'000. * nm).in(m).numerical_value_in(nm) == 15'000.);
|
||||
|
||||
template<template<auto, typename> typename Q>
|
||||
concept invalid_unit_conversion = requires {
|
||||
requires !requires { Q<isq::length[m], int>(2000 * m).in(km); }; // truncating conversion
|
||||
@@ -901,7 +908,7 @@ static_assert(1 * si::si2019::speed_of_light_in_vacuum == 299'792'458 * isq::spe
|
||||
|
||||
// Different named dimensions
|
||||
template<Reference auto R1, Reference auto R2>
|
||||
inline constexpr bool invalid_comparison = !requires { 2 * R1 == 2 * R2; } && !requires { 2 * R2 == 2 * R1; };
|
||||
constexpr bool invalid_comparison = !requires { 2 * R1 == 2 * R2; } && !requires { 2 * R2 == 2 * R1; };
|
||||
static_assert(invalid_comparison<isq::activity[Bq], isq::frequency[Hz]>);
|
||||
|
||||
|
||||
|
@@ -31,7 +31,7 @@ import std;
|
||||
#endif
|
||||
|
||||
template<auto V, typename T>
|
||||
inline constexpr bool is_of_type = std::is_same_v<MP_UNITS_REMOVE_CONST(decltype(V)), T>;
|
||||
constexpr bool is_of_type = std::is_same_v<MP_UNITS_REMOVE_CONST(decltype(V)), T>;
|
||||
|
||||
// NOLINTBEGIN(cppcoreguidelines-macro-usage)
|
||||
#if MP_UNITS_API_NO_CRTP
|
||||
|
Reference in New Issue
Block a user