Merge branch 'master' of github.com:mpusz/mp-units

This commit is contained in:
Mateusz Pusz
2024-02-16 15:46:44 +01:00
21 changed files with 254 additions and 188 deletions

View File

@@ -47,7 +47,7 @@ jobs:
# name: "MSVC 14.2", # name: "MSVC 14.2",
# os: windows-2019, # os: windows-2019,
# compiler: { type: VISUAL, version: 16, cc: "", cxx: "" }, # compiler: { type: VISUAL, version: 16, cc: "", cxx: "" },
# conan-config: "-c user.build:skip_la=True", # conan-config: "-c user.mp-units.build:skip_la=True",
# } # }
# - { # - {
# name: "MSVC 14.3", # name: "MSVC 14.3",
@@ -212,7 +212,7 @@ jobs:
run: | run: |
conan create . --user mpusz --channel ${CHANNEL} --lockfile-out=package.lock \ conan create . --user mpusz --channel ${CHANNEL} --lockfile-out=package.lock \
-b mp-units/* -b missing -c tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" \ -b mp-units/* -b missing -c tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" \
-c user.build:all=True -o cxx_modules=${{ matrix.config.cxx_modules }} -o use_fmtlib=${{ env.use_fmtlib }} ${{ matrix.config.conan-config }} -c user.mp-units.build:all=True -o cxx_modules=${{ matrix.config.cxx_modules }} -o use_fmtlib=${{ env.use_fmtlib }} ${{ matrix.config.conan-config }}
- name: Obtain package reference - name: Obtain package reference
id: get-package-ref id: get-package-ref
shell: bash shell: bash

View File

@@ -205,7 +205,7 @@ jobs:
- name: Install Conan dependencies - name: Install Conan dependencies
shell: bash shell: bash
run: | run: |
conan install . -b missing -c tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" -c user.build:all=False \ conan install . -b missing -c tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" -c user.mp-units.build:all=False \
-o cxx_modules=${{ matrix.config.cxx_modules }} -o use_fmtlib=${{ env.use_fmtlib }} -o cxx_modules=${{ matrix.config.cxx_modules }} -o use_fmtlib=${{ env.use_fmtlib }}
mv CMakeUserPresets.json src mv CMakeUserPresets.json src
- name: Configure mp-units CMake - name: Configure mp-units CMake

View File

@@ -105,7 +105,7 @@ jobs:
conan profile detect --force conan profile detect --force
conan remote add artifactory https://mpusz.jfrog.io/artifactory/api/conan/conan-oss conan remote add artifactory https://mpusz.jfrog.io/artifactory/api/conan/conan-oss
mkdir _lgtm_build_dir && cd _lgtm_build_dir mkdir _lgtm_build_dir && cd _lgtm_build_dir
conan build .. -s compiler.cppstd=20 -c user.build:all=True -o use_fmtlib=True -b missing conan build .. -s compiler.cppstd=20 -c user.mp-units.build:all=True -o use_fmtlib=True -b missing
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2 uses: github/codeql-action/analyze@v2

View File

@@ -70,17 +70,17 @@ tasks:
gp sync-await python-init gp sync-await python-init
conan profile detect conan profile detect
conan config install $PWD/.gitpod/conan conan config install $PWD/.gitpod/conan
conan install . -pr gcc12 -c user.build:all=True -o use_fmtlib=True -b missing conan install . -pr gcc12 -o use_fmtlib=True -b missing
conan install . -pr gcc12 -c user.build:all=True -o use_fmtlib=True -b missing -s build_type=Debug conan install . -pr gcc12 -o use_fmtlib=True -b missing -s build_type=Debug
gp sync-done conan-gcc12-20 gp sync-done conan-gcc12-20
conan install . -pr gcc13 -c user.build:all=True -b missing conan install . -pr gcc13 -b missing
conan install . -pr gcc13 -c user.build:all=True -b missing -s build_type=Debug conan install . -pr gcc13 -b missing -s build_type=Debug
gp sync-done conan-gcc13-20 gp sync-done conan-gcc13-20
conan install . -pr clang16 -c user.build:all=True -o use_fmtlib=True -b missing conan install . -pr clang16 -o use_fmtlib=True -b missing
conan install . -pr clang16 -c user.build:all=True -o use_fmtlib=True -b missing -s build_type=Debug conan install . -pr clang16 -o use_fmtlib=True -b missing -s build_type=Debug
gp sync-done conan-clang16-20 gp sync-done conan-clang16-20
conan install . -pr clang17 -c user.build:all=True -o cxx_modules=True -b missing conan install . -pr clang17 -o cxx_modules=True -b missing
conan install . -pr clang17 -c user.build:all=True -o cxx_modules=True -b missing -s build_type=Debug conan install . -pr clang17 -o cxx_modules=True -b missing -s build_type=Debug
gp sync-done conan-clang17-20 gp sync-done conan-clang17-20
conan remote login -p $ARTIFACTORY_TOKEN conan-gitpod-mp-units $ARTIFACTORY_USER conan remote login -p $ARTIFACTORY_TOKEN conan-gitpod-mp-units $ARTIFACTORY_USER
conan upload "*" -r conan-gitpod-mp-units -c conan upload "*" -r conan-gitpod-mp-units -c
@@ -88,29 +88,29 @@ tasks:
init: | init: |
gp sync-await conan-gcc12-20 gp sync-await conan-gcc12-20
source ${PYTHON_VENV}/bin/activate source ${PYTHON_VENV}/bin/activate
conan build . -pr gcc12 -c user.build:all=True -o use_fmtlib=True conan build . -pr gcc12 -o use_fmtlib=True
conan build . -pr gcc12 -c user.build:all=True -o use_fmtlib=True -s build_type=Debug conan build . -pr gcc12 -o use_fmtlib=True -s build_type=Debug
echo "🛠️ gcc-12 pre-build done for C++20, header files, and libfmt! You can close this terminal and use 'Build' button in the VSCode status bar for incremental builds. 🛠️" echo "🛠️ gcc-12 pre-build done for C++20, header files, and libfmt! You can close this terminal and use 'Build' button in the VSCode status bar for incremental builds. 🛠️"
- name: gcc-13-20 - name: gcc-13-20
init: | init: |
gp sync-await conan-gcc13-20 gp sync-await conan-gcc13-20
source ${PYTHON_VENV}/bin/activate source ${PYTHON_VENV}/bin/activate
conan build . -pr gcc13 -c user.build:all=True conan build . -pr gcc13
conan build . -pr gcc13 -c user.build:all=True -s build_type=Debug conan build . -pr gcc13 -s build_type=Debug
echo "🛠️ gcc-13 pre-build done for C++20 and header files! You can close this terminal and use 'Build' button in the VSCode status bar for incremental builds. 🛠️" echo "🛠️ gcc-13 pre-build done for C++20 and header files! You can close this terminal and use 'Build' button in the VSCode status bar for incremental builds. 🛠️"
- name: clang-16-20 - name: clang-16-20
init: | init: |
gp sync-await conan-clang16-20 gp sync-await conan-clang16-20
source ${PYTHON_VENV}/bin/activate source ${PYTHON_VENV}/bin/activate
conan build . -pr clang16 -c user.build:all=True -o use_fmtlib=True conan build . -pr clang16 -o use_fmtlib=True
conan build . -pr clang16 -c user.build:all=True -o use_fmtlib=True -s build_type=Debug conan build . -pr clang16 -o use_fmtlib=True -s build_type=Debug
echo "🛠️ clang-16 pre-build done for C++20, header files, and libfmt! You can close this terminal and use 'Build' button in the VSCode status bar for incremental builds. 🛠️" echo "🛠️ clang-16 pre-build done for C++20, header files, and libfmt! You can close this terminal and use 'Build' button in the VSCode status bar for incremental builds. 🛠️"
- name: clang-17-20 - name: clang-17-20
init: | init: |
gp sync-await conan-clang17-20 gp sync-await conan-clang17-20
source ${PYTHON_VENV}/bin/activate source ${PYTHON_VENV}/bin/activate
conan build . -pr clang17 -c user.build:all=True -o cxx_modules=True conan build . -pr clang17 -o cxx_modules=True
conan build . -pr clang17 -c user.build:all=True -o cxx_modules=True -s build_type=Debug conan build . -pr clang17 -o cxx_modules=True -s build_type=Debug
echo "🛠️ clang-17 pre-build done for C++20! You can close this terminal and use 'Build' button in the VSCode status bar for incremental builds. 🛠️" echo "🛠️ clang-17 pre-build done for C++20! You can close this terminal and use 'Build' button in the VSCode status bar for incremental builds. 🛠️"
- name: documentation - name: documentation
init: | init: |

View File

@@ -1,2 +1,3 @@
tools.cmake.cmaketoolchain:generator=Ninja Multi-Config tools.cmake.cmaketoolchain:generator=Ninja Multi-Config
tools.cmake.cmake_layout:build_folder_vars=["settings.compiler", "settings.compiler.version", "settings.compiler.cppstd"] tools.cmake.cmake_layout:build_folder_vars=["settings.compiler", "settings.compiler.version", "settings.compiler.cppstd"]
user.mp-units.build:all=True

View File

@@ -56,13 +56,21 @@ After the script is done please make sure to stage all those changes to git comm
The simplest way to verify if all targets build correctly and all unit tests pass is to run: The simplest way to verify if all targets build correctly and all unit tests pass is to run:
```bash ```bash
conan build . -pr <your_conan_profile> -s compiler.cppstd=23 -o cxx_modules=True -c user.build:all=True -b missing 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 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) [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. 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
```
### Backward Compatibility ### Backward Compatibility
Before submission, please remember to check if the code compiles fine on the supported compilers. Before submission, please remember to check if the code compiles fine on the supported compilers.

View File

@@ -83,7 +83,7 @@ class MPUnitsConan(ConanFile):
return { return {
"gcc": "12", "gcc": "12",
"clang": "16", "clang": "16",
"apple-clang": "15" "apple-clang": "15",
# , "msvc": "192" # , "msvc": "192"
} }
@@ -91,18 +91,18 @@ class MPUnitsConan(ConanFile):
def _std_format_minimum_compilers_version(self): def _std_format_minimum_compilers_version(self):
return { return {
"gcc": "13", "gcc": "13",
"clang": "17" "clang": "17",
# , "apple-clang": "15" # , "apple-clang": "15"
# , "msvc": "192" # , "msvc": "192"
} }
@property @property
def _build_all(self): def _build_all(self):
return bool(self.conf.get("user.build:all", default=False)) return bool(self.conf.get("user.mp-units.build:all", default=False))
@property @property
def _skip_la(self): def _skip_la(self):
return bool(self.conf.get("user.build:skip_la", default=False)) return bool(self.conf.get("user.mp-units.build:skip_la", default=False))
def set_version(self): def set_version(self):
content = load(self, os.path.join(self.recipe_folder, "src/CMakeLists.txt")) content = load(self, os.path.join(self.recipe_folder, "src/CMakeLists.txt"))

View File

@@ -194,9 +194,9 @@ tools.build:compiler_executables={"c": "gcc-12", "cpp": "g++-12"}
### Conan configuration properties ### Conan configuration properties
[`user.build:all`](#user-build-all){ #user-build-all } [`user.mp-units.build:all`](#user.mp-units.build-all){ #user.mp-units.build-all }
: [:octicons-tag-24: 0.8.0][build all support] · :octicons-milestone-24: `True`/`False` (Default: `False`) : [:octicons-tag-24: 2.2.0][build all support] · :octicons-milestone-24: `True`/`False` (Default: `False`)
Enables compilation of all the source code, including tests and examples. To support this, it requires some additional Conan build dependencies described in Enables compilation of all the source code, including tests and examples. To support this, it requires some additional Conan build dependencies described in
[Repository Structure and Dependencies](#repository-structure-and-dependencies). [Repository Structure and Dependencies](#repository-structure-and-dependencies).
@@ -204,19 +204,19 @@ tools.build:compiler_executables={"c": "gcc-12", "cpp": "g++-12"}
[`tools.build:skip_test`](https://docs.conan.io/2/reference/commands/config.html?highlight=tools.build:skip_test#conan-config-list) [`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`). configuration property is set to `True`).
[build all support]: https://github.com/mpusz/mp-units/releases/tag/v0.8.0 [build all support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
[`user.build:skip_la`](#user-skip-la){ #user-skip-la } [`user.mp-units.build:skip_la`](#user-skip-la){ #user-skip-la }
: [:octicons-tag-24: 0.8.0][skip la support] · :octicons-milestone-24: `True`/`False` (Default: `False`) : [:octicons-tag-24: 2.2.0][skip la support] · :octicons-milestone-24: `True`/`False` (Default: `False`)
If `user.build:all` is enabled, among others, Conan installs the external 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) [wg21-linear_algebra](https://conan.io/center/recipes/wg21-linear_algebra)
dependency and enables the compilation of linear algebra-based tests and usage examples. dependency and enables the compilation of linear algebra-based tests and usage examples.
Such behavior can be disabled with this option. Such behavior can be disabled with this option.
[skip la support]: https://github.com/mpusz/mp-units/releases/tag/v0.8.0 [skip la support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
### CMake options ### CMake options
@@ -453,11 +453,11 @@ In case you would like to build all the **mp-units** source code (with unit test
you should: you should:
1. Use the _CMakeLists.txt_ from the top-level directory. 1. Use the _CMakeLists.txt_ from the top-level directory.
2. Run Conan with [`user.build:all`](#user-build-all) = `True`. 2. Run Conan with [`user.mp-units.build:all`](#user.mp-units.build-all) = `True`.
```shell ```shell
git clone https://github.com/mpusz/mp-units.git && cd units 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.build:all=True -b missing 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, The above will download and install all of the dependencies needed for the development of the library,
@@ -504,7 +504,7 @@ After that, you can either:
To test CMake installation and Conan packaging or create a Conan package run: To test CMake installation and Conan packaging or create a Conan package run:
```shell ```shell
conan create . --user <username> --channel <channel> -pr <your_conan_profile> -s compiler.cppstd=20 -o cxx_modules=True -c user.build:all=True -b missing 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. The above will create a Conan package and run tests provided in _./test_package_ directory.

View File

@@ -392,4 +392,9 @@ static_assert(same_type<kind_of<isq::length> / isq::time, isq::length / isq::tim
Only a root quantity from the hierarchy tree or the one marked with `is_kind` specifier Only a root quantity from the hierarchy tree or the one marked with `is_kind` specifier
in the `quantity_spec` definition can be put as a template parameter to the `kind_of` in the `quantity_spec` definition can be put as a template parameter to the `kind_of`
specifier. For example, `kind_of<isq::width>` will fail to compile. specifier. For example, `kind_of<isq::width>` will fail to compile. However, we can call
`get_kind(q)` to obtain a kind of any quantity:
```cpp
static_assert(get_kind(isq::width) == kind_of<isq::length>);
```

View File

@@ -50,13 +50,13 @@ QuantityOf<isq::mechanical_energy> auto total_energy(QuantityOf<isq::momentum> a
void si_example() void si_example()
{ {
using namespace mp_units::si::unit_symbols; using namespace mp_units::si::unit_symbols;
constexpr auto GeV = si::giga<si::electronvolt>; constexpr Unit auto GeV = si::giga<si::electronvolt>;
constexpr QuantityOf<isq::speed> auto c = 1. * si::si2019::speed_of_light_in_vacuum; constexpr quantity c = 1. * si::si2019::speed_of_light_in_vacuum;
auto c2 = pow<2>(c); quantity c2 = pow<2>(c);
const auto p1 = isq::momentum(4. * GeV / c); const quantity p1 = isq::momentum(4. * GeV / c);
const QuantityOf<isq::mass> auto m1 = 3. * GeV / c2; const QuantityOf<isq::mass> auto m1 = 3. * GeV / c2;
const auto E = total_energy(p1, m1, c); const quantity E = total_energy(p1, m1, c);
std::cout << "\n*** SI units (c = " << c << " = " << c.in(si::metre / s) << ") ***\n"; std::cout << "\n*** SI units (c = " << c << " = " << c.in(si::metre / s) << ") ***\n";
@@ -65,18 +65,18 @@ void si_example()
<< "m = " << m1 << "\n" << "m = " << m1 << "\n"
<< "E = " << E << "\n"; << "E = " << E << "\n";
const auto p2 = p1.in(GeV / (m / s)); const quantity p2 = p1.in(GeV / (m / s));
const auto m2 = m1.in(GeV / pow<2>(m / s)); const quantity m2 = m1.in(GeV / pow<2>(m / s));
const auto E2 = total_energy(p2, m2, c).in(GeV); const quantity E2 = total_energy(p2, m2, c).in(GeV);
std::cout << "\n[in `GeV`]\n" std::cout << "\n[in `GeV`]\n"
<< "p = " << p2 << "\n" << "p = " << p2 << "\n"
<< "m = " << m2 << "\n" << "m = " << m2 << "\n"
<< "E = " << E2 << "\n"; << "E = " << E2 << "\n";
const auto p3 = p1.in(kg * m / s); const quantity p3 = p1.in(kg * m / s);
const auto m3 = m1.in(kg); const quantity m3 = m1.in(kg);
const auto E3 = total_energy(p3, m3, c).in(J); const quantity E3 = total_energy(p3, m3, c).in(J);
std::cout << "\n[in SI base units]\n" std::cout << "\n[in SI base units]\n"
<< "p = " << p3 << "\n" << "p = " << p3 << "\n"
@@ -92,10 +92,10 @@ void natural_example()
using namespace mp_units::natural; using namespace mp_units::natural;
using namespace mp_units::natural::unit_symbols; using namespace mp_units::natural::unit_symbols;
constexpr auto c = 1. * speed_of_light; constexpr quantity c = 1. * speed_of_light;
const auto p = 4. * momentum[GeV]; const quantity p = 4. * momentum[GeV];
const auto m = 3. * mass[GeV]; const quantity m = 3. * mass[GeV];
const auto E = total_energy(p, m, c); const quantity E = total_energy(p, m, c);
std::cout << "\n*** Natural units (c = " << c << ") ***\n" std::cout << "\n*** Natural units (c = " << c << ") ***\n"
<< "p = " << p << "\n" << "p = " << p << "\n"

View File

@@ -83,7 +83,7 @@
// TODO revise the below when clang-18 is released // TODO revise the below when clang-18 is released
#if MP_UNITS_COMP_CLANG >= 18 && !defined __cpp_explicit_this_parameter #if MP_UNITS_COMP_CLANG >= 18 && !defined __cpp_explicit_this_parameter
#define __cpp_explicit_this_parameter #define __cpp_explicit_this_parameter 202110L
#endif #endif

View File

@@ -130,7 +130,7 @@ concept QuantitySpec =
detail::NamedQuantitySpec<T> || detail::IntermediateDerivedQuantitySpec<T> || detail::QuantityKindSpec<T>; detail::NamedQuantitySpec<T> || detail::IntermediateDerivedQuantitySpec<T> || detail::QuantityKindSpec<T>;
template<QuantitySpec Q> template<QuantitySpec Q>
[[nodiscard]] consteval QuantitySpec auto get_kind(Q q); [[nodiscard]] consteval detail::QuantityKindSpec auto get_kind(Q q);
namespace detail { namespace detail {
@@ -138,7 +138,7 @@ template<auto To, auto From>
concept NestedQuantityKindSpecOf = concept NestedQuantityKindSpecOf =
QuantitySpec<std::remove_const_t<decltype(From)>> && QuantitySpec<std::remove_const_t<decltype(To)>> && QuantitySpec<std::remove_const_t<decltype(From)>> && QuantitySpec<std::remove_const_t<decltype(To)>> &&
get_kind(From) != get_kind(To) && get_kind(From) != get_kind(To) &&
std::derived_from<std::remove_cvref_t<decltype(To)>, std::remove_cvref_t<decltype(get_kind(From))>>; std::derived_from<std::remove_cvref_t<decltype(To)>, std::remove_cvref_t<decltype(get_kind(From)._quantity_spec_)>>;
} }

View File

@@ -444,11 +444,15 @@ namespace detail {
template<typename T> template<typename T>
concept QuantitySpecWithNoSpecifiers = detail::NamedQuantitySpec<T> || detail::IntermediateDerivedQuantitySpec<T>; concept QuantitySpecWithNoSpecifiers = detail::NamedQuantitySpec<T> || detail::IntermediateDerivedQuantitySpec<T>;
template<QuantitySpec Q>
[[nodiscard]] consteval QuantitySpec auto get_kind_tree_root(Q q);
} // namespace detail } // namespace detail
#ifdef __cpp_explicit_this_parameter #ifdef __cpp_explicit_this_parameter
template<auto Q> template<auto Q>
requires(detail::QuantitySpecWithNoSpecifiers<std::remove_const_t<decltype(Q)>>) && (get_kind(Q) == Q) requires(detail::QuantitySpecWithNoSpecifiers<std::remove_const_t<decltype(Q)>>) &&
(detail::get_kind_tree_root(Q) == Q)
struct kind_of_<Q> : std::remove_const_t<decltype(Q)> { struct kind_of_<Q> : std::remove_const_t<decltype(Q)> {
static constexpr auto _quantity_spec_ = Q; static constexpr auto _quantity_spec_ = Q;
}; };
@@ -456,10 +460,11 @@ struct kind_of_<Q> : std::remove_const_t<decltype(Q)> {
#if MP_UNITS_COMP_CLANG #if MP_UNITS_COMP_CLANG
template<auto Q> template<auto Q>
requires detail::QuantitySpecWithNoSpecifiers<std::remove_cvref_t<decltype(Q)>> && (get_kind(Q) == Q) requires detail::QuantitySpecWithNoSpecifiers<std::remove_cvref_t<decltype(Q)>> &&
(detail::get_kind_tree_root(Q) == Q)
#else #else
template<detail::QuantitySpecWithNoSpecifiers auto Q> template<detail::QuantitySpecWithNoSpecifiers auto Q>
requires(get_kind(Q) == Q) requires(detail::get_kind_tree_root(Q) == Q)
#endif #endif
struct kind_of_<Q> : quantity_spec<kind_of_<Q>, Q> { struct kind_of_<Q> : quantity_spec<kind_of_<Q>, Q> {
static constexpr auto _quantity_spec_ = Q; static constexpr auto _quantity_spec_ = Q;
@@ -467,7 +472,7 @@ struct kind_of_<Q> : quantity_spec<kind_of_<Q>, Q> {
#endif #endif
template<detail::QuantitySpecWithNoSpecifiers auto Q> template<detail::QuantitySpecWithNoSpecifiers auto Q>
requires(get_kind(Q) == Q) requires(detail::get_kind_tree_root(Q) == Q)
inline constexpr kind_of_<Q> kind_of; inline constexpr kind_of_<Q> kind_of;
namespace detail { namespace detail {
@@ -484,6 +489,15 @@ template<QuantitySpec auto... From, QuantitySpec Q>
return q; return q;
} }
template<QuantitySpec Q>
[[nodiscard]] consteval auto remove_kind(Q q)
{
if constexpr (detail::QuantityKindSpec<Q>)
return Q::_quantity_spec_;
else
return q;
}
} // namespace detail } // namespace detail
// Operators // Operators
@@ -493,7 +507,7 @@ template<QuantitySpec Lhs, QuantitySpec Rhs>
{ {
return detail::clone_kind_of<Lhs{}, Rhs{}>( return detail::clone_kind_of<Lhs{}, Rhs{}>(
detail::expr_multiply<derived_quantity_spec, struct dimensionless, detail::type_list_of_quantity_spec_less>( detail::expr_multiply<derived_quantity_spec, struct dimensionless, detail::type_list_of_quantity_spec_less>(
remove_kind(lhs), remove_kind(rhs))); detail::remove_kind(lhs), detail::remove_kind(rhs)));
} }
template<QuantitySpec Lhs, QuantitySpec Rhs> template<QuantitySpec Lhs, QuantitySpec Rhs>
@@ -501,7 +515,7 @@ template<QuantitySpec Lhs, QuantitySpec Rhs>
{ {
return detail::clone_kind_of<Lhs{}, Rhs{}>( return detail::clone_kind_of<Lhs{}, Rhs{}>(
detail::expr_divide<derived_quantity_spec, struct dimensionless, detail::type_list_of_quantity_spec_less>( detail::expr_divide<derived_quantity_spec, struct dimensionless, detail::type_list_of_quantity_spec_less>(
remove_kind(lhs), remove_kind(rhs))); detail::remove_kind(lhs), detail::remove_kind(rhs)));
} }
template<QuantitySpec Lhs, QuantitySpec Rhs> template<QuantitySpec Lhs, QuantitySpec Rhs>
@@ -538,13 +552,13 @@ template<std::intmax_t Num, std::intmax_t Den = 1, QuantitySpec Q>
else if constexpr (detail::IntermediateDerivedQuantitySpec<Q>) else if constexpr (detail::IntermediateDerivedQuantitySpec<Q>)
return detail::clone_kind_of<Q{}>( return detail::clone_kind_of<Q{}>(
detail::expr_pow<Num, Den, derived_quantity_spec, struct dimensionless, detail::type_list_of_quantity_spec_less>( detail::expr_pow<Num, Den, derived_quantity_spec, struct dimensionless, detail::type_list_of_quantity_spec_less>(
remove_kind(q))); detail::remove_kind(q)));
else if constexpr (Den == 1) else if constexpr (Den == 1)
return detail::clone_kind_of<Q{}>( return detail::clone_kind_of<Q{}>(
derived_quantity_spec<power<std::remove_const_t<decltype(remove_kind(Q{}))>, Num>>{}); derived_quantity_spec<power<std::remove_const_t<decltype(detail::remove_kind(Q{}))>, Num>>{});
else else
return detail::clone_kind_of<Q{}>( return detail::clone_kind_of<Q{}>(
derived_quantity_spec<power<std::remove_const_t<decltype(remove_kind(Q{}))>, Num, Den>>{}); derived_quantity_spec<power<std::remove_const_t<decltype(detail::remove_kind(Q{}))>, Num, Den>>{});
} }
@@ -1315,8 +1329,8 @@ template<QuantitySpec From, QuantitySpec To>
else if constexpr (From{} == To{}) else if constexpr (From{} == To{})
return yes; return yes;
else if constexpr (QuantityKindSpec<From> || QuantityKindSpec<To>) { else if constexpr (QuantityKindSpec<From> || QuantityKindSpec<To>) {
constexpr auto from_kind = get_kind(From{}); constexpr auto from_kind = get_kind_tree_root(From{});
constexpr auto to_kind = get_kind(To{}); constexpr auto to_kind = get_kind_tree_root(To{});
constexpr auto exploded_kind_result = [](specs_convertible_result res) { constexpr auto exploded_kind_result = [](specs_convertible_result res) {
using enum specs_convertible_result; using enum specs_convertible_result;
return res == no ? no : yes; return res == no ? no : yes;
@@ -1327,11 +1341,11 @@ template<QuantitySpec From, QuantitySpec To>
return convertible_impl(from_kind, to_kind); return convertible_impl(from_kind, to_kind);
else if constexpr (get_complexity(from_kind) > get_complexity(to_kind)) else if constexpr (get_complexity(from_kind) > get_complexity(to_kind))
return exploded_kind_result( return exploded_kind_result(
convertible_impl(get_kind(explode<get_complexity(to_kind)>(from_kind).quantity), to_kind)); convertible_impl(get_kind_tree_root(explode<get_complexity(to_kind)>(from_kind).quantity), to_kind));
else else
return exploded_kind_result( return exploded_kind_result(
convertible_impl(from_kind, get_kind(explode<get_complexity(from_kind)>(to_kind).quantity))); convertible_impl(from_kind, get_kind_tree_root(explode<get_complexity(from_kind)>(to_kind).quantity)));
} else if constexpr (NestedQuantityKindSpecOf<get_kind(To{}), from> && get_kind(To{}) == To{}) } else if constexpr (NestedQuantityKindSpecOf<get_kind_tree_root(To{}), from> && get_kind_tree_root(To{}) == To{})
return yes; return yes;
else if constexpr (NamedQuantitySpec<From> && NamedQuantitySpec<To>) { else if constexpr (NamedQuantitySpec<From> && NamedQuantitySpec<To>) {
if constexpr (have_common_base(From{}, To{})) { if constexpr (have_common_base(From{}, To{})) {
@@ -1401,8 +1415,8 @@ template<QuantitySpec QS1, QuantitySpec QS2>
namespace detail { namespace detail {
template<QuantitySpec Q> template<QuantitySpec Q>
requires requires(Q q) { get_kind(q); } requires requires(Q q) { get_kind_tree_root(q); }
using to_kind = std::remove_const_t<decltype(get_kind(Q{}))>; using to_kind = std::remove_const_t<decltype(get_kind_tree_root(Q{}))>;
#ifdef __cpp_explicit_this_parameter #ifdef __cpp_explicit_this_parameter
template<NamedQuantitySpec auto QS, auto... Args> template<NamedQuantitySpec auto QS, auto... Args>
@@ -1415,19 +1429,8 @@ template<typename Self, NamedQuantitySpec auto QS, auto... Args>
return contains<struct is_kind, Args...>(); return contains<struct is_kind, Args...>();
} }
} // namespace detail
template<QuantitySpec Q> template<QuantitySpec Q>
[[nodiscard]] consteval auto remove_kind(Q q) [[nodiscard]] consteval QuantitySpec auto get_kind_tree_root(Q q)
{
if constexpr (detail::QuantityKindSpec<Q>)
return Q::_quantity_spec_;
else
return q;
}
template<QuantitySpec Q>
[[nodiscard]] consteval QuantitySpec auto get_kind(Q q)
{ {
auto defined_as_kind = []<typename QQ>(QQ qq) { auto defined_as_kind = []<typename QQ>(QQ qq) {
if constexpr (requires { detail::defined_as_kind(qq); }) if constexpr (requires { detail::defined_as_kind(qq); })
@@ -1441,7 +1444,7 @@ template<QuantitySpec Q>
} else if constexpr (defined_as_kind(Q{})) { } else if constexpr (defined_as_kind(Q{})) {
return q; return q;
} else if constexpr (requires { Q::_parent_; }) { } else if constexpr (requires { Q::_parent_; }) {
return get_kind(Q::_parent_); return get_kind_tree_root(Q::_parent_);
} else if constexpr (detail::IntermediateDerivedQuantitySpec<Q>) { } else if constexpr (detail::IntermediateDerivedQuantitySpec<Q>) {
return detail::expr_map<detail::to_kind, derived_quantity_spec, struct dimensionless, return detail::expr_map<detail::to_kind, derived_quantity_spec, struct dimensionless,
detail::type_list_of_quantity_spec_less>(q); detail::type_list_of_quantity_spec_less>(q);
@@ -1451,20 +1454,29 @@ template<QuantitySpec Q>
} }
} }
} // namespace detail
template<QuantitySpec Q>
[[nodiscard]] consteval detail::QuantityKindSpec auto get_kind(Q q)
{
return kind_of<detail::get_kind_tree_root(q)>;
}
[[nodiscard]] consteval QuantitySpec auto common_quantity_spec(QuantitySpec auto q) { return q; } [[nodiscard]] consteval QuantitySpec auto common_quantity_spec(QuantitySpec auto q) { return q; }
template<QuantitySpec Q1, QuantitySpec Q2> template<QuantitySpec Q1, QuantitySpec Q2>
[[nodiscard]] consteval QuantitySpec auto common_quantity_spec(Q1 q1, Q2 q2) [[nodiscard]] consteval QuantitySpec auto common_quantity_spec(Q1 q1, Q2 q2)
requires(implicitly_convertible(get_kind(q1), get_kind(q2)) || implicitly_convertible(get_kind(q2), get_kind(q1))) requires(implicitly_convertible(get_kind_tree_root(q1), get_kind_tree_root(q2)) ||
implicitly_convertible(get_kind_tree_root(q2), get_kind_tree_root(q1)))
{ {
using QQ1 = std::remove_const_t<decltype(remove_kind(q1))>; using QQ1 = std::remove_const_t<decltype(detail::remove_kind(q1))>;
using QQ2 = std::remove_const_t<decltype(remove_kind(q2))>; using QQ2 = std::remove_const_t<decltype(detail::remove_kind(q2))>;
if constexpr (is_same_v<Q1, Q2>) if constexpr (is_same_v<Q1, Q2>)
return q1; return q1;
else if constexpr (detail::NestedQuantityKindSpecOf<Q1{}, Q2{}>) else if constexpr (detail::NestedQuantityKindSpecOf<Q1{}, Q2{}>)
return remove_kind(q1); return detail::remove_kind(q1);
else if constexpr (detail::NestedQuantityKindSpecOf<Q2{}, Q1{}>) else if constexpr (detail::NestedQuantityKindSpecOf<Q2{}, Q1{}>)
return remove_kind(q2); return detail::remove_kind(q2);
else if constexpr ((detail::QuantityKindSpec<Q1> && !detail::QuantityKindSpec<Q2>) || else if constexpr ((detail::QuantityKindSpec<Q1> && !detail::QuantityKindSpec<Q2>) ||
(detail::IntermediateDerivedQuantitySpec<QQ1> && detail::NamedQuantitySpec<QQ2> && (detail::IntermediateDerivedQuantitySpec<QQ1> && detail::NamedQuantitySpec<QQ2> &&
implicitly_convertible(Q1{}, Q2{}))) implicitly_convertible(Q1{}, Q2{})))
@@ -1479,10 +1491,10 @@ template<QuantitySpec Q1, QuantitySpec Q2>
return q2; return q2;
else if constexpr (implicitly_convertible(Q2{}, Q1{})) else if constexpr (implicitly_convertible(Q2{}, Q1{}))
return q1; return q1;
else if constexpr (implicitly_convertible(get_kind(Q1{}), get_kind(Q2{}))) else if constexpr (implicitly_convertible(get_kind_tree_root(Q1{}), get_kind_tree_root(Q2{})))
return get_kind(q2); return get_kind_tree_root(q2);
else else
return get_kind(q1); return get_kind_tree_root(q1);
} }
[[nodiscard]] consteval QuantitySpec auto common_quantity_spec(QuantitySpec auto q1, QuantitySpec auto q2, [[nodiscard]] consteval QuantitySpec auto common_quantity_spec(QuantitySpec auto q1, QuantitySpec auto q2,

View File

@@ -27,23 +27,23 @@
namespace mp_units::iec80000 { namespace mp_units::iec80000 {
// clang-format off // clang-format off
template<PrefixableUnit auto U> struct kibi_ : prefixed_unit<"Ki", mag_power<2, 10>, U> {}; template<PrefixableUnit U> struct kibi_ : prefixed_unit<"Ki", mag_power<2, 10>, U{}> {};
template<PrefixableUnit auto U> struct mebi_ : prefixed_unit<"Mi", mag_power<2, 20>, U> {}; template<PrefixableUnit U> struct mebi_ : prefixed_unit<"Mi", mag_power<2, 20>, U{}> {};
template<PrefixableUnit auto U> struct gibi_ : prefixed_unit<"Gi", mag_power<2, 30>, U> {}; template<PrefixableUnit U> struct gibi_ : prefixed_unit<"Gi", mag_power<2, 30>, U{}> {};
template<PrefixableUnit auto U> struct tebi_ : prefixed_unit<"Ti", mag_power<2, 40>, U> {}; template<PrefixableUnit U> struct tebi_ : prefixed_unit<"Ti", mag_power<2, 40>, U{}> {};
template<PrefixableUnit auto U> struct pebi_ : prefixed_unit<"Pi", mag_power<2, 50>, U> {}; template<PrefixableUnit U> struct pebi_ : prefixed_unit<"Pi", mag_power<2, 50>, U{}> {};
template<PrefixableUnit auto U> struct exbi_ : prefixed_unit<"Ei", mag_power<2, 60>, U> {}; template<PrefixableUnit U> struct exbi_ : prefixed_unit<"Ei", mag_power<2, 60>, U{}> {};
template<PrefixableUnit auto U> struct zebi_ : prefixed_unit<"Zi", mag_power<2, 70>, U> {}; template<PrefixableUnit U> struct zebi_ : prefixed_unit<"Zi", mag_power<2, 70>, U{}> {};
template<PrefixableUnit auto U> struct yobi_ : prefixed_unit<"Yi", mag_power<2, 80>, U> {}; template<PrefixableUnit U> struct yobi_ : prefixed_unit<"Yi", mag_power<2, 80>, U{}> {};
template<PrefixableUnit auto U> inline constexpr kibi_<U> kibi; template<PrefixableUnit auto U> inline constexpr kibi_<std::remove_const_t<decltype(U)>> kibi;
template<PrefixableUnit auto U> inline constexpr mebi_<U> mebi; template<PrefixableUnit auto U> inline constexpr mebi_<std::remove_const_t<decltype(U)>> mebi;
template<PrefixableUnit auto U> inline constexpr gibi_<U> gibi; template<PrefixableUnit auto U> inline constexpr gibi_<std::remove_const_t<decltype(U)>> gibi;
template<PrefixableUnit auto U> inline constexpr tebi_<U> tebi; template<PrefixableUnit auto U> inline constexpr tebi_<std::remove_const_t<decltype(U)>> tebi;
template<PrefixableUnit auto U> inline constexpr pebi_<U> pebi; template<PrefixableUnit auto U> inline constexpr pebi_<std::remove_const_t<decltype(U)>> pebi;
template<PrefixableUnit auto U> inline constexpr exbi_<U> exbi; template<PrefixableUnit auto U> inline constexpr exbi_<std::remove_const_t<decltype(U)>> exbi;
template<PrefixableUnit auto U> inline constexpr zebi_<U> zebi; template<PrefixableUnit auto U> inline constexpr zebi_<std::remove_const_t<decltype(U)>> zebi;
template<PrefixableUnit auto U> inline constexpr yobi_<U> yobi; template<PrefixableUnit auto U> inline constexpr yobi_<std::remove_const_t<decltype(U)>> yobi;
// clang-format on // clang-format on
} // namespace mp_units::iec80000 } // namespace mp_units::iec80000

View File

@@ -27,55 +27,55 @@
namespace mp_units::si { namespace mp_units::si {
// clang-format off // clang-format off
template<PrefixableUnit auto U> struct quecto_ : prefixed_unit<"q", mag_power<10, -30>, U> {}; template<PrefixableUnit U> struct quecto_ : prefixed_unit<"q", mag_power<10, -30>, U{}> {};
template<PrefixableUnit auto U> struct ronto_ : prefixed_unit<"r", mag_power<10, -27>, U> {}; template<PrefixableUnit U> struct ronto_ : prefixed_unit<"r", mag_power<10, -27>, U{}> {};
template<PrefixableUnit auto U> struct yocto_ : prefixed_unit<"y", mag_power<10, -24>, U> {}; template<PrefixableUnit U> struct yocto_ : prefixed_unit<"y", mag_power<10, -24>, U{}> {};
template<PrefixableUnit auto U> struct zepto_ : prefixed_unit<"z", mag_power<10, -21>, U> {}; template<PrefixableUnit U> struct zepto_ : prefixed_unit<"z", mag_power<10, -21>, U{}> {};
template<PrefixableUnit auto U> struct atto_ : prefixed_unit<"a", mag_power<10, -18>, U> {}; template<PrefixableUnit U> struct atto_ : prefixed_unit<"a", mag_power<10, -18>, U{}> {};
template<PrefixableUnit auto U> struct femto_ : prefixed_unit<"f", mag_power<10, -15>, U> {}; template<PrefixableUnit U> struct femto_ : prefixed_unit<"f", mag_power<10, -15>, U{}> {};
template<PrefixableUnit auto U> struct pico_ : prefixed_unit<"p", mag_power<10, -12>, U> {}; template<PrefixableUnit U> struct pico_ : prefixed_unit<"p", mag_power<10, -12>, U{}> {};
template<PrefixableUnit auto U> struct nano_ : prefixed_unit<"n", mag_power<10, -9>, U> {}; template<PrefixableUnit U> struct nano_ : prefixed_unit<"n", mag_power<10, -9>, U{}> {};
template<PrefixableUnit auto U> struct micro_ : prefixed_unit<basic_symbol_text{"µ", "u"}, mag_power<10, -6>, U> {}; template<PrefixableUnit U> struct micro_ : prefixed_unit<basic_symbol_text{"µ", "u"}, mag_power<10, -6>, U{}> {};
template<PrefixableUnit auto U> struct milli_ : prefixed_unit<"m", mag_power<10, -3>, U> {}; template<PrefixableUnit U> struct milli_ : prefixed_unit<"m", mag_power<10, -3>, U{}> {};
template<PrefixableUnit auto U> struct centi_ : prefixed_unit<"c", mag_power<10, -2>, U> {}; template<PrefixableUnit U> struct centi_ : prefixed_unit<"c", mag_power<10, -2>, U{}> {};
template<PrefixableUnit auto U> struct deci_ : prefixed_unit<"d", mag_power<10, -1>, U> {}; template<PrefixableUnit U> struct deci_ : prefixed_unit<"d", mag_power<10, -1>, U{}> {};
template<PrefixableUnit auto U> struct deca_ : prefixed_unit<"da", mag_power<10, 1>, U> {}; template<PrefixableUnit U> struct deca_ : prefixed_unit<"da", mag_power<10, 1>, U{}> {};
template<PrefixableUnit auto U> struct hecto_ : prefixed_unit<"h", mag_power<10, 2>, U> {}; template<PrefixableUnit U> struct hecto_ : prefixed_unit<"h", mag_power<10, 2>, U{}> {};
template<PrefixableUnit auto U> struct kilo_ : prefixed_unit<"k", mag_power<10, 3>, U> {}; template<PrefixableUnit U> struct kilo_ : prefixed_unit<"k", mag_power<10, 3>, U{}> {};
template<PrefixableUnit auto U> struct mega_ : prefixed_unit<"M", mag_power<10, 6>, U> {}; template<PrefixableUnit U> struct mega_ : prefixed_unit<"M", mag_power<10, 6>, U{}> {};
template<PrefixableUnit auto U> struct giga_ : prefixed_unit<"G", mag_power<10, 9>, U> {}; template<PrefixableUnit U> struct giga_ : prefixed_unit<"G", mag_power<10, 9>, U{}> {};
template<PrefixableUnit auto U> struct tera_ : prefixed_unit<"T", mag_power<10, 12>, U> {}; template<PrefixableUnit U> struct tera_ : prefixed_unit<"T", mag_power<10, 12>, U{}> {};
template<PrefixableUnit auto U> struct peta_ : prefixed_unit<"P", mag_power<10, 15>, U> {}; template<PrefixableUnit U> struct peta_ : prefixed_unit<"P", mag_power<10, 15>, U{}> {};
template<PrefixableUnit auto U> struct exa_ : prefixed_unit<"E", mag_power<10, 18>, U> {}; template<PrefixableUnit U> struct exa_ : prefixed_unit<"E", mag_power<10, 18>, U{}> {};
template<PrefixableUnit auto U> struct zetta_ : prefixed_unit<"Z", mag_power<10, 21>, U> {}; template<PrefixableUnit U> struct zetta_ : prefixed_unit<"Z", mag_power<10, 21>, U{}> {};
template<PrefixableUnit auto U> struct yotta_ : prefixed_unit<"Y", mag_power<10, 24>, U> {}; template<PrefixableUnit U> struct yotta_ : prefixed_unit<"Y", mag_power<10, 24>, U{}> {};
template<PrefixableUnit auto U> struct ronna_ : prefixed_unit<"R", mag_power<10, 27>, U> {}; template<PrefixableUnit U> struct ronna_ : prefixed_unit<"R", mag_power<10, 27>, U{}> {};
template<PrefixableUnit auto U> struct quetta_ : prefixed_unit<"Q", mag_power<10, 30>, U> {}; template<PrefixableUnit U> struct quetta_ : prefixed_unit<"Q", mag_power<10, 30>, U{}> {};
template<PrefixableUnit auto U> inline constexpr quecto_<U> quecto; template<PrefixableUnit auto U> inline constexpr quecto_<std::remove_const_t<decltype(U)>> quecto;
template<PrefixableUnit auto U> inline constexpr ronto_<U> ronto; template<PrefixableUnit auto U> inline constexpr ronto_<std::remove_const_t<decltype(U)>> ronto;
template<PrefixableUnit auto U> inline constexpr yocto_<U> yocto; template<PrefixableUnit auto U> inline constexpr yocto_<std::remove_const_t<decltype(U)>> yocto;
template<PrefixableUnit auto U> inline constexpr zepto_<U> zepto; template<PrefixableUnit auto U> inline constexpr zepto_<std::remove_const_t<decltype(U)>> zepto;
template<PrefixableUnit auto U> inline constexpr atto_<U> atto; template<PrefixableUnit auto U> inline constexpr atto_<std::remove_const_t<decltype(U)>> atto;
template<PrefixableUnit auto U> inline constexpr femto_<U> femto; template<PrefixableUnit auto U> inline constexpr femto_<std::remove_const_t<decltype(U)>> femto;
template<PrefixableUnit auto U> inline constexpr pico_<U> pico; template<PrefixableUnit auto U> inline constexpr pico_<std::remove_const_t<decltype(U)>> pico;
template<PrefixableUnit auto U> inline constexpr nano_<U> nano; template<PrefixableUnit auto U> inline constexpr nano_<std::remove_const_t<decltype(U)>> nano;
template<PrefixableUnit auto U> inline constexpr micro_<U> micro; template<PrefixableUnit auto U> inline constexpr micro_<std::remove_const_t<decltype(U)>> micro;
template<PrefixableUnit auto U> inline constexpr milli_<U> milli; template<PrefixableUnit auto U> inline constexpr milli_<std::remove_const_t<decltype(U)>> milli;
template<PrefixableUnit auto U> inline constexpr centi_<U> centi; template<PrefixableUnit auto U> inline constexpr centi_<std::remove_const_t<decltype(U)>> centi;
template<PrefixableUnit auto U> inline constexpr deci_<U> deci; template<PrefixableUnit auto U> inline constexpr deci_<std::remove_const_t<decltype(U)>> deci;
template<PrefixableUnit auto U> inline constexpr deca_<U> deca; template<PrefixableUnit auto U> inline constexpr deca_<std::remove_const_t<decltype(U)>> deca;
template<PrefixableUnit auto U> inline constexpr hecto_<U> hecto; template<PrefixableUnit auto U> inline constexpr hecto_<std::remove_const_t<decltype(U)>> hecto;
template<PrefixableUnit auto U> inline constexpr kilo_<U> kilo; template<PrefixableUnit auto U> inline constexpr kilo_<std::remove_const_t<decltype(U)>> kilo;
template<PrefixableUnit auto U> inline constexpr mega_<U> mega; template<PrefixableUnit auto U> inline constexpr mega_<std::remove_const_t<decltype(U)>> mega;
template<PrefixableUnit auto U> inline constexpr giga_<U> giga; template<PrefixableUnit auto U> inline constexpr giga_<std::remove_const_t<decltype(U)>> giga;
template<PrefixableUnit auto U> inline constexpr tera_<U> tera; template<PrefixableUnit auto U> inline constexpr tera_<std::remove_const_t<decltype(U)>> tera;
template<PrefixableUnit auto U> inline constexpr peta_<U> peta; template<PrefixableUnit auto U> inline constexpr peta_<std::remove_const_t<decltype(U)>> peta;
template<PrefixableUnit auto U> inline constexpr exa_<U> exa; template<PrefixableUnit auto U> inline constexpr exa_<std::remove_const_t<decltype(U)>> exa;
template<PrefixableUnit auto U> inline constexpr zetta_<U> zetta; template<PrefixableUnit auto U> inline constexpr zetta_<std::remove_const_t<decltype(U)>> zetta;
template<PrefixableUnit auto U> inline constexpr yotta_<U> yotta; template<PrefixableUnit auto U> inline constexpr yotta_<std::remove_const_t<decltype(U)>> yotta;
template<PrefixableUnit auto U> inline constexpr ronna_<U> ronna; template<PrefixableUnit auto U> inline constexpr ronna_<std::remove_const_t<decltype(U)>> ronna;
template<PrefixableUnit auto U> inline constexpr quetta_<U> quetta; template<PrefixableUnit auto U> inline constexpr quetta_<std::remove_const_t<decltype(U)>> quetta;
// clang-format on // clang-format on
} // namespace mp_units::si } // namespace mp_units::si

View File

@@ -24,7 +24,7 @@ cmake_minimum_required(VERSION 3.5)
find_package(Catch2 3 REQUIRED) find_package(Catch2 3 REQUIRED)
add_executable(unit_tests_runtime distribution_test.cpp fmt_test.cpp math_test.cpp) add_executable(unit_tests_runtime distribution_test.cpp fmt_test.cpp math_test.cpp atomic_test.cpp)
if(${projectPrefix}BUILD_CXX_MODULES) if(${projectPrefix}BUILD_CXX_MODULES)
target_compile_definitions(unit_tests_runtime PUBLIC ${projectPrefix}MODULES) target_compile_definitions(unit_tests_runtime PUBLIC ${projectPrefix}MODULES)
endif() endif()

View File

@@ -0,0 +1,37 @@
// The MIT License (MIT)
//
// Copyright (c) 2024 Nick Thompson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <catch2/catch_all.hpp>
#include <mp-units/systems/isq/space_and_time.h>
#include <mp-units/systems/si/unit_symbols.h>
#include <mp-units/systems/si/units.h>
#include <atomic>
using namespace mp_units;
using namespace mp_units::si::unit_symbols;
TEST_CASE("std::atomic works with dimensioned types", "[atomic][assignment]")
{
std::atomic<quantity<isq::area[m2]>> a1 = 3.0 * isq::area[m2];
std::atomic<quantity<isq::area[m2]>> a2 = 3.0 * isq::area[m2];
REQUIRE(a1.load() == a2.load());
}

View File

@@ -396,25 +396,25 @@ static_assert(acceleration * (time * time) != position_vector);
static_assert(acceleration / speed != frequency); static_assert(acceleration / speed != frequency);
// get_kind // get_kind
static_assert(get_kind(length) == length); static_assert(get_kind(length) == kind_of<length>);
static_assert(get_kind(distance) == length); static_assert(get_kind(distance) == kind_of<length>);
static_assert(get_kind(time) == time); static_assert(get_kind(time) == kind_of<time>);
static_assert(get_kind(period_duration) == time); static_assert(get_kind(period_duration) == kind_of<time>);
static_assert(get_kind(length / time) == length / time); static_assert(get_kind(length / time) == kind_of<length / time>);
static_assert(get_kind(speed) == speed); static_assert(get_kind(speed) == kind_of<speed>);
static_assert(get_kind(height / time) == length / time); static_assert(get_kind(height / time) == kind_of<length / time>);
static_assert(get_kind(inverse(time)) == inverse(time)); static_assert(get_kind(inverse(time)) == kind_of<inverse(time)>);
static_assert(get_kind(inverse(period_duration)) == inverse(time)); static_assert(get_kind(inverse(period_duration)) == kind_of<inverse(time)>);
static_assert(get_kind(frequency) == frequency); static_assert(get_kind(frequency) == kind_of<frequency>);
static_assert(get_kind(mass * frequency) == mass * frequency); static_assert(get_kind(mass * frequency) == kind_of<mass * frequency>);
static_assert(get_kind(moment_of_force) == moment_of_force); static_assert(get_kind(moment_of_force) == kind_of<moment_of_force>);
static_assert(get_kind(energy) == energy); static_assert(get_kind(energy) == kind_of<energy>);
static_assert(get_kind(potential_energy) == energy); static_assert(get_kind(potential_energy) == kind_of<energy>);
static_assert(get_kind(kinetic_energy) == energy); static_assert(get_kind(kinetic_energy) == kind_of<energy>);
static_assert(get_kind(pow<1, 2>(area)) == pow<1, 2>(area)); static_assert(get_kind(pow<1, 2>(area)) == kind_of<pow<1, 2>(area)>);
static_assert(get_kind(angular_measure) == angular_measure); static_assert(get_kind(angular_measure) == kind_of<angular_measure>);
static_assert(get_kind(phase_angle) == angular_measure); static_assert(get_kind(phase_angle) == kind_of<angular_measure>);
static_assert(get_kind(rotational_displacement) == angular_measure); static_assert(get_kind(rotational_displacement) == kind_of<angular_measure>);
// comparisons of the same dimensions // comparisons of the same dimensions
static_assert(length == length); static_assert(length == length);
@@ -507,7 +507,7 @@ static_assert(convertible_impl(width, width) == yes);
static_assert(convertible_impl(energy, energy) == yes); static_assert(convertible_impl(energy, energy) == yes);
static_assert(convertible_impl(kind_of<length>, kind_of<length>) == yes); static_assert(convertible_impl(kind_of<length>, kind_of<length>) == yes);
static_assert(convertible_impl(kind_of<energy>, kind_of<energy>) == yes); static_assert(convertible_impl(kind_of<energy>, kind_of<energy>) == yes);
static_assert(convertible_impl(kind_of<get_kind(moment_of_force)>, kind_of<get_kind(moment_of_force)>) == yes); static_assert(convertible_impl(get_kind(moment_of_force), get_kind(moment_of_force)) == yes);
// converting to a different branch // converting to a different branch
static_assert(convertible_impl(height, width) == cast); static_assert(convertible_impl(height, width) == cast);

View File

@@ -520,7 +520,8 @@ static_assert(is_of_type<1 * percent * (1 * m), quantity<derived_unit<struct per
static_assert(is_of_type<1 * m / (1 * s), quantity<derived_unit<struct si::metre, per<struct si::second>>{}, int>>); static_assert(is_of_type<1 * m / (1 * s), quantity<derived_unit<struct si::metre, per<struct si::second>>{}, int>>);
static_assert(is_of_type<1 * m / (1 * m), quantity<one, int>>); static_assert(is_of_type<1 * m / (1 * m), quantity<one, int>>);
static_assert(is_of_type<1 * km / (1 * m), quantity<derived_unit<si::kilo_<si::metre>, per<struct si::metre>>{}, int>>); static_assert(
is_of_type<1 * km / (1 * m), quantity<derived_unit<si::kilo_<struct si::metre>, per<struct si::metre>>{}, int>>);
static_assert(is_of_type<1 * m / 1, quantity<si::metre, int>>); static_assert(is_of_type<1 * m / 1, quantity<si::metre, int>>);
static_assert(is_of_type<1 * m / (1 * one), quantity<si::metre, int>>); static_assert(is_of_type<1 * m / (1 * one), quantity<si::metre, int>>);
@@ -568,7 +569,7 @@ static_assert(is_of_type<1 * percent * (1. * m), quantity<derived_unit<struct pe
static_assert(is_of_type<1 * m / (1. * s), quantity<derived_unit<struct si::metre, per<struct si::second>>{}, double>>); static_assert(is_of_type<1 * m / (1. * s), quantity<derived_unit<struct si::metre, per<struct si::second>>{}, double>>);
static_assert(is_of_type<1. * m / (1 * m), quantity<one, double>>); static_assert(is_of_type<1. * m / (1 * m), quantity<one, double>>);
static_assert( static_assert(
is_of_type<1. * km / (1 * m), quantity<derived_unit<si::kilo_<si::metre>, per<struct si::metre>>{}, double>>); is_of_type<1. * km / (1 * m), quantity<derived_unit<si::kilo_<struct si::metre>, per<struct si::metre>>{}, double>>);
static_assert(is_of_type<1. * m / 1, quantity<si::metre, double>>); static_assert(is_of_type<1. * m / 1, quantity<si::metre, double>>);
static_assert(is_of_type<1 * m / (1. * one), quantity<si::metre, double>>); static_assert(is_of_type<1 * m / (1. * one), quantity<si::metre, double>>);
@@ -612,11 +613,12 @@ static_assert(is_of_type<1 * m * (1 * min), quantity<derived_unit<struct si::met
static_assert(is_of_type<1 * s * (1 * Hz), quantity<derived_unit<struct si::hertz, struct si::second>{}, int>>); static_assert(is_of_type<1 * s * (1 * Hz), quantity<derived_unit<struct si::hertz, struct si::second>{}, int>>);
static_assert(is_of_type<1 / (1 * min), quantity<derived_unit<struct one, per<struct si::minute>>{}, int>>); static_assert(is_of_type<1 / (1 * min), quantity<derived_unit<struct one, per<struct si::minute>>{}, int>>);
static_assert(is_of_type<1 / (1 * Hz), quantity<derived_unit<struct one, per<struct si::hertz>>{}, int>>); static_assert(is_of_type<1 / (1 * Hz), quantity<derived_unit<struct one, per<struct si::hertz>>{}, int>>);
static_assert(is_of_type<1 / (1 * km), quantity<derived_unit<struct one, per<si::kilo_<si::metre>>>{}, int>>); static_assert(is_of_type<1 / (1 * km), quantity<derived_unit<struct one, per<si::kilo_<struct si::metre>>>{}, int>>);
static_assert(is_of_type<1 / min, quantity<derived_unit<struct one, per<struct si::minute>>{}, int>>); static_assert(is_of_type<1 / min, quantity<derived_unit<struct one, per<struct si::minute>>{}, int>>);
static_assert(is_of_type<1 / Hz, quantity<derived_unit<struct one, per<struct si::hertz>>{}, int>>); static_assert(is_of_type<1 / Hz, quantity<derived_unit<struct one, per<struct si::hertz>>{}, int>>);
static_assert(is_of_type<1 / km, quantity<derived_unit<struct one, per<si::kilo_<si::metre>>>{}, int>>); static_assert(is_of_type<1 / km, quantity<derived_unit<struct one, per<si::kilo_<struct si::metre>>>{}, int>>);
static_assert(is_of_type<1 * km / (1 * m), quantity<derived_unit<si::kilo_<si::metre>, per<struct si::metre>>{}, int>>); static_assert(
is_of_type<1 * km / (1 * m), quantity<derived_unit<si::kilo_<struct si::metre>, per<struct si::metre>>{}, int>>);
static_assert(is_of_type<1 * m / (1 * s), quantity<derived_unit<struct si::metre, per<struct si::second>>{}, int>>); static_assert(is_of_type<1 * m / (1 * s), quantity<derived_unit<struct si::metre, per<struct si::second>>{}, int>>);
static_assert(is_of_type<1 * m / (1 * min), quantity<derived_unit<struct si::metre, per<struct si::minute>>{}, int>>); static_assert(is_of_type<1 * m / (1 * min), quantity<derived_unit<struct si::metre, per<struct si::minute>>{}, int>>);
static_assert(is_of_type<1 * min / (1 * m), quantity<derived_unit<struct si::minute, per<struct si::metre>>{}, int>>); static_assert(is_of_type<1 * min / (1 * m), quantity<derived_unit<struct si::minute, per<struct si::metre>>{}, int>>);

View File

@@ -61,8 +61,9 @@ static_assert(1 * Rm == 1'000'000'000'000'000'000 * Gm);
static_assert(1 * Qm == 1'000'000'000'000'000'000 * Tm); static_assert(1 * Qm == 1'000'000'000'000'000'000 * Tm);
// check for invalid prefixes // check for invalid prefixes
template<template<auto U> typename prefix, auto V1> template<template<typename U> typename prefix, auto V1>
concept can_not_be_prefixed = Unit<std::remove_const_t<decltype(V1)>> && !requires { typename prefix<V1>; }; concept can_not_be_prefixed =
Unit<std::remove_const_t<decltype(V1)>> && !requires { typename prefix<std::remove_const_t<decltype(V1)>>; };
static_assert(can_not_be_prefixed<si::milli_, si::degree_Celsius>); static_assert(can_not_be_prefixed<si::milli_, si::degree_Celsius>);
static_assert(can_not_be_prefixed<si::milli_, si::minute>); static_assert(can_not_be_prefixed<si::milli_, si::minute>);

View File

@@ -212,8 +212,8 @@ static_assert(convertible(kilojoule, joule));
static_assert(kilojoule != joule); static_assert(kilojoule != joule);
static_assert(kilojoule.symbol == "kJ"); static_assert(kilojoule.symbol == "kJ");
static_assert(is_of_type<si::kilo<metre>, si::kilo_<metre>>); static_assert(is_of_type<si::kilo<metre>, si::kilo_<metre_>>);
static_assert(is_of_type<si::kilo<joule>, si::kilo_<joule>>); static_assert(is_of_type<si::kilo<joule>, si::kilo_<joule_>>);
// TODO Should the below be a scaled version of metre^2? // TODO Should the below be a scaled version of metre^2?
static_assert(is_of_type<kilometre * metre, derived_unit<kilometre_, metre_>>); // !!! static_assert(is_of_type<kilometre * metre, derived_unit<kilometre_, metre_>>); // !!!
@@ -264,7 +264,7 @@ static_assert(is_of_type<get_canonical_unit(km_2).reference_unit, metre_>);
static_assert(get_canonical_unit(km_2).mag == mag<2000>); static_assert(get_canonical_unit(km_2).mag == mag<2000>);
constexpr auto kJ_42 = mag<42> * si::kilo<joule>; constexpr auto kJ_42 = mag<42> * si::kilo<joule>;
static_assert(is_of_type<kJ_42, scaled_unit<mag<42>, si::kilo_<joule>>>); static_assert(is_of_type<kJ_42, scaled_unit<mag<42>, si::kilo_<joule_>>>);
static_assert( static_assert(
is_of_type<get_canonical_unit(kJ_42).reference_unit, derived_unit<gram_, power<metre_, 2>, per<power<second_, 2>>>>); is_of_type<get_canonical_unit(kJ_42).reference_unit, derived_unit<gram_, power<metre_, 2>, per<power<second_, 2>>>>);
static_assert(get_canonical_unit(kJ_42).mag == mag<42'000'000>); static_assert(get_canonical_unit(kJ_42).mag == mag<42'000'000>);
@@ -467,7 +467,7 @@ static_assert(!convertible(metre, metre* metre));
// one // one
static_assert(is_of_type<metre / metre, one_>); static_assert(is_of_type<metre / metre, one_>);
static_assert(is_of_type<si::kilo<metre> / metre, derived_unit<si::kilo_<metre>, per<metre_>>>); static_assert(is_of_type<si::kilo<metre> / metre, derived_unit<si::kilo_<metre_>, per<metre_>>>);
static_assert(metre / metre == one); static_assert(metre / metre == one);
static_assert(hertz * second == one); static_assert(hertz * second == one);
static_assert(one * one == one); static_assert(one * one == one);
@@ -509,7 +509,7 @@ static_assert(is_of_type<pow<1, 2>(metre / (second * second)), derived_unit<powe
static_assert(is_of_type<kilometre * kilometre, derived_unit<power<kilometre_, 2>>>); static_assert(is_of_type<kilometre * kilometre, derived_unit<power<kilometre_, 2>>>);
static_assert(is_of_type<pow<2>(kilometre), derived_unit<power<kilometre_, 2>>>); static_assert(is_of_type<pow<2>(kilometre), derived_unit<power<kilometre_, 2>>>);
static_assert(is_of_type<pow<2>(si::kilo<metre>), derived_unit<power<si::kilo_<metre>, 2>>>); static_assert(is_of_type<pow<2>(si::kilo<metre>), derived_unit<power<si::kilo_<metre_>, 2>>>);
static_assert(is_of_type<pow<2>(hour), derived_unit<power<hour_, 2>>>); static_assert(is_of_type<pow<2>(hour), derived_unit<power<hour_, 2>>>);
static_assert( static_assert(
is_of_type<pow<2>(mag<3600>* second), scaled_unit<mag<3600> * mag<3600>, derived_unit<power<second_, 2>>>>); is_of_type<pow<2>(mag<3600>* second), scaled_unit<mag<3600> * mag<3600>, derived_unit<power<second_, 2>>>>);