diff --git a/.github/workflows/ci-conan.yml b/.github/workflows/ci-conan.yml index 52b4955c..6a154b8b 100644 --- a/.github/workflows/ci-conan.yml +++ b/.github/workflows/ci-conan.yml @@ -47,7 +47,7 @@ jobs: # name: "MSVC 14.2", # os: windows-2019, # 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", @@ -212,7 +212,7 @@ jobs: run: | conan create . --user mpusz --channel ${CHANNEL} --lockfile-out=package.lock \ -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 id: get-package-ref shell: bash diff --git a/.github/workflows/ci-test-package-cmake.yml b/.github/workflows/ci-test-package-cmake.yml index a24bbefb..82000cb9 100644 --- a/.github/workflows/ci-test-package-cmake.yml +++ b/.github/workflows/ci-test-package-cmake.yml @@ -205,7 +205,7 @@ jobs: - name: Install Conan dependencies shell: bash 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 }} mv CMakeUserPresets.json src - name: Configure mp-units CMake diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index d8464ae8..6f29802c 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -105,7 +105,7 @@ jobs: conan profile detect --force conan remote add artifactory https://mpusz.jfrog.io/artifactory/api/conan/conan-oss 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 uses: github/codeql-action/analyze@v2 diff --git a/.gitpod.yml b/.gitpod.yml index 3b18bd77..17b99026 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -70,17 +70,17 @@ tasks: gp sync-await python-init conan profile detect 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 -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 + conan install . -pr gcc12 -o use_fmtlib=True -b missing -s build_type=Debug gp sync-done conan-gcc12-20 - conan install . -pr gcc13 -c user.build:all=True -b missing - conan install . -pr gcc13 -c user.build:all=True -b missing -s build_type=Debug + conan install . -pr gcc13 -b missing + conan install . -pr gcc13 -b missing -s build_type=Debug 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 -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 + conan install . -pr clang16 -o use_fmtlib=True -b missing -s build_type=Debug 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 -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 + conan install . -pr clang17 -o cxx_modules=True -b missing -s build_type=Debug gp sync-done conan-clang17-20 conan remote login -p $ARTIFACTORY_TOKEN conan-gitpod-mp-units $ARTIFACTORY_USER conan upload "*" -r conan-gitpod-mp-units -c @@ -88,29 +88,29 @@ tasks: init: | gp sync-await conan-gcc12-20 source ${PYTHON_VENV}/bin/activate - conan build . -pr gcc12 -c user.build:all=True -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 + 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. 🛠️" - name: gcc-13-20 init: | gp sync-await conan-gcc13-20 source ${PYTHON_VENV}/bin/activate - conan build . -pr gcc13 -c user.build:all=True - conan build . -pr gcc13 -c user.build:all=True -s build_type=Debug + conan build . -pr gcc13 + 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. 🛠️" - name: clang-16-20 init: | gp sync-await conan-clang16-20 source ${PYTHON_VENV}/bin/activate - conan build . -pr clang16 -c user.build:all=True -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 + 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. 🛠️" - name: clang-17-20 init: | gp sync-await conan-clang17-20 source ${PYTHON_VENV}/bin/activate - conan build . -pr clang17 -c user.build:all=True -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 + 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. 🛠️" - name: documentation init: | diff --git a/.gitpod/conan/global.conf b/.gitpod/conan/global.conf index 6840876c..29ce8bd5 100644 --- a/.gitpod/conan/global.conf +++ b/.gitpod/conan/global.conf @@ -1,2 +1,3 @@ tools.cmake.cmaketoolchain:generator=Ninja Multi-Config tools.cmake.cmake_layout:build_folder_vars=["settings.compiler", "settings.compiler.version", "settings.compiler.cppstd"] +user.mp-units.build:all=True diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 32f4730b..ae27af60 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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: ```bash -conan build . -pr -s compiler.cppstd=23 -o cxx_modules=True -c user.build:all=True -b missing +conan build . -pr -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 +``` + + ### Backward Compatibility Before submission, please remember to check if the code compiles fine on the supported compilers. diff --git a/conanfile.py b/conanfile.py index 2825223b..aab04f5c 100644 --- a/conanfile.py +++ b/conanfile.py @@ -83,7 +83,7 @@ class MPUnitsConan(ConanFile): return { "gcc": "12", "clang": "16", - "apple-clang": "15" + "apple-clang": "15", # , "msvc": "192" } @@ -91,18 +91,18 @@ class MPUnitsConan(ConanFile): def _std_format_minimum_compilers_version(self): return { "gcc": "13", - "clang": "17" + "clang": "17", # , "apple-clang": "15" # , "msvc": "192" } @property 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 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): content = load(self, os.path.join(self.recipe_folder, "src/CMakeLists.txt")) diff --git a/docs/getting_started/installation_and_usage.md b/docs/getting_started/installation_and_usage.md index 0ebf89c6..1dca2e2a 100644 --- a/docs/getting_started/installation_and_usage.md +++ b/docs/getting_started/installation_and_usage.md @@ -194,9 +194,9 @@ tools.build:compiler_executables={"c": "gcc-12", "cpp": "g++-12"} ### 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 [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) 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) dependency and enables the compilation of linear algebra-based tests and usage examples. Such behavior can be disabled with this option. - [skip la support]: https://github.com/mpusz/mp-units/releases/tag/v0.8.0 + [skip la support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0 ### CMake options @@ -453,11 +453,11 @@ In case you would like to build all the **mp-units** source code (with unit test you should: 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 git clone https://github.com/mpusz/mp-units.git && cd units -conan build . -pr -s compiler.cppstd=23 -o cxx_modules=True -c user.build:all=True -b missing +conan build . -pr -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, @@ -504,7 +504,7 @@ After that, you can either: To test CMake installation and Conan packaging or create a Conan package run: ```shell -conan create . --user --channel -pr -s compiler.cppstd=20 -o cxx_modules=True -c user.build:all=True -b missing +conan create . --user --channel -pr -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. diff --git a/docs/users_guide/framework_basics/systems_of_quantities.md b/docs/users_guide/framework_basics/systems_of_quantities.md index 080972bb..c87e493f 100644 --- a/docs/users_guide/framework_basics/systems_of_quantities.md +++ b/docs/users_guide/framework_basics/systems_of_quantities.md @@ -392,4 +392,9 @@ static_assert(same_type / isq::time, isq::length / isq::tim 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` - specifier. For example, `kind_of` will fail to compile. + specifier. For example, `kind_of` 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); + ``` diff --git a/example/total_energy.cpp b/example/total_energy.cpp index f183169b..aea49059 100644 --- a/example/total_energy.cpp +++ b/example/total_energy.cpp @@ -50,13 +50,13 @@ QuantityOf auto total_energy(QuantityOf a void si_example() { using namespace mp_units::si::unit_symbols; - constexpr auto GeV = si::giga; - constexpr QuantityOf auto c = 1. * si::si2019::speed_of_light_in_vacuum; - auto c2 = pow<2>(c); + constexpr Unit auto GeV = si::giga; + constexpr quantity c = 1. * si::si2019::speed_of_light_in_vacuum; + quantity c2 = pow<2>(c); - const auto p1 = isq::momentum(4. * GeV / c); + const quantity p1 = isq::momentum(4. * GeV / c); const QuantityOf 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"; @@ -65,18 +65,18 @@ void si_example() << "m = " << m1 << "\n" << "E = " << E << "\n"; - const auto p2 = p1.in(GeV / (m / s)); - const auto m2 = m1.in(GeV / pow<2>(m / s)); - const auto E2 = total_energy(p2, m2, c).in(GeV); + const quantity p2 = p1.in(GeV / (m / s)); + const quantity m2 = m1.in(GeV / pow<2>(m / s)); + const quantity E2 = total_energy(p2, m2, c).in(GeV); std::cout << "\n[in `GeV`]\n" << "p = " << p2 << "\n" << "m = " << m2 << "\n" << "E = " << E2 << "\n"; - const auto p3 = p1.in(kg * m / s); - const auto m3 = m1.in(kg); - const auto E3 = total_energy(p3, m3, c).in(J); + const quantity p3 = p1.in(kg * m / s); + const quantity m3 = m1.in(kg); + const quantity E3 = total_energy(p3, m3, c).in(J); std::cout << "\n[in SI base units]\n" << "p = " << p3 << "\n" @@ -92,10 +92,10 @@ void natural_example() using namespace mp_units::natural; using namespace mp_units::natural::unit_symbols; - constexpr auto c = 1. * speed_of_light; - const auto p = 4. * momentum[GeV]; - const auto m = 3. * mass[GeV]; - const auto E = total_energy(p, m, c); + constexpr quantity c = 1. * speed_of_light; + const quantity p = 4. * momentum[GeV]; + const quantity m = 3. * mass[GeV]; + const quantity E = total_energy(p, m, c); std::cout << "\n*** Natural units (c = " << c << ") ***\n" << "p = " << p << "\n" diff --git a/src/core/include/mp-units/bits/external/hacks.h b/src/core/include/mp-units/bits/external/hacks.h index cbe2b05b..a24a884a 100644 --- a/src/core/include/mp-units/bits/external/hacks.h +++ b/src/core/include/mp-units/bits/external/hacks.h @@ -83,7 +83,7 @@ // TODO revise the below when clang-18 is released #if MP_UNITS_COMP_CLANG >= 18 && !defined __cpp_explicit_this_parameter -#define __cpp_explicit_this_parameter +#define __cpp_explicit_this_parameter 202110L #endif diff --git a/src/core/include/mp-units/bits/quantity_spec_concepts.h b/src/core/include/mp-units/bits/quantity_spec_concepts.h index d685c923..9ee2b690 100644 --- a/src/core/include/mp-units/bits/quantity_spec_concepts.h +++ b/src/core/include/mp-units/bits/quantity_spec_concepts.h @@ -130,7 +130,7 @@ concept QuantitySpec = detail::NamedQuantitySpec || detail::IntermediateDerivedQuantitySpec || detail::QuantityKindSpec; template -[[nodiscard]] consteval QuantitySpec auto get_kind(Q q); +[[nodiscard]] consteval detail::QuantityKindSpec auto get_kind(Q q); namespace detail { @@ -138,7 +138,7 @@ template concept NestedQuantityKindSpecOf = QuantitySpec> && QuantitySpec> && get_kind(From) != get_kind(To) && - std::derived_from, std::remove_cvref_t>; + std::derived_from, std::remove_cvref_t>; } diff --git a/src/core/include/mp-units/quantity_spec.h b/src/core/include/mp-units/quantity_spec.h index ae958d04..2b25b8a7 100644 --- a/src/core/include/mp-units/quantity_spec.h +++ b/src/core/include/mp-units/quantity_spec.h @@ -444,11 +444,15 @@ namespace detail { template concept QuantitySpecWithNoSpecifiers = detail::NamedQuantitySpec || detail::IntermediateDerivedQuantitySpec; +template +[[nodiscard]] consteval QuantitySpec auto get_kind_tree_root(Q q); + } // namespace detail #ifdef __cpp_explicit_this_parameter template - requires(detail::QuantitySpecWithNoSpecifiers>) && (get_kind(Q) == Q) + requires(detail::QuantitySpecWithNoSpecifiers>) && + (detail::get_kind_tree_root(Q) == Q) struct kind_of_ : std::remove_const_t { static constexpr auto _quantity_spec_ = Q; }; @@ -456,10 +460,11 @@ struct kind_of_ : std::remove_const_t { #if MP_UNITS_COMP_CLANG template - requires detail::QuantitySpecWithNoSpecifiers> && (get_kind(Q) == Q) + requires detail::QuantitySpecWithNoSpecifiers> && + (detail::get_kind_tree_root(Q) == Q) #else template - requires(get_kind(Q) == Q) + requires(detail::get_kind_tree_root(Q) == Q) #endif struct kind_of_ : quantity_spec, Q> { static constexpr auto _quantity_spec_ = Q; @@ -467,7 +472,7 @@ struct kind_of_ : quantity_spec, Q> { #endif template - requires(get_kind(Q) == Q) + requires(detail::get_kind_tree_root(Q) == Q) inline constexpr kind_of_ kind_of; namespace detail { @@ -484,6 +489,15 @@ template return q; } +template +[[nodiscard]] consteval auto remove_kind(Q q) +{ + if constexpr (detail::QuantityKindSpec) + return Q::_quantity_spec_; + else + return q; +} + } // namespace detail // Operators @@ -493,7 +507,7 @@ template { return detail::clone_kind_of( detail::expr_multiply( - remove_kind(lhs), remove_kind(rhs))); + detail::remove_kind(lhs), detail::remove_kind(rhs))); } template @@ -501,7 +515,7 @@ template { return detail::clone_kind_of( detail::expr_divide( - remove_kind(lhs), remove_kind(rhs))); + detail::remove_kind(lhs), detail::remove_kind(rhs))); } template @@ -538,13 +552,13 @@ template else if constexpr (detail::IntermediateDerivedQuantitySpec) return detail::clone_kind_of( detail::expr_pow( - remove_kind(q))); + detail::remove_kind(q))); else if constexpr (Den == 1) return detail::clone_kind_of( - derived_quantity_spec, Num>>{}); + derived_quantity_spec, Num>>{}); else return detail::clone_kind_of( - derived_quantity_spec, Num, Den>>{}); + derived_quantity_spec, Num, Den>>{}); } @@ -1315,8 +1329,8 @@ template else if constexpr (From{} == To{}) return yes; else if constexpr (QuantityKindSpec || QuantityKindSpec) { - constexpr auto from_kind = get_kind(From{}); - constexpr auto to_kind = get_kind(To{}); + constexpr auto from_kind = get_kind_tree_root(From{}); + constexpr auto to_kind = get_kind_tree_root(To{}); constexpr auto exploded_kind_result = [](specs_convertible_result res) { using enum specs_convertible_result; return res == no ? no : yes; @@ -1327,11 +1341,11 @@ template return convertible_impl(from_kind, to_kind); else if constexpr (get_complexity(from_kind) > get_complexity(to_kind)) return exploded_kind_result( - convertible_impl(get_kind(explode(from_kind).quantity), to_kind)); + convertible_impl(get_kind_tree_root(explode(from_kind).quantity), to_kind)); else return exploded_kind_result( - convertible_impl(from_kind, get_kind(explode(to_kind).quantity))); - } else if constexpr (NestedQuantityKindSpecOf && get_kind(To{}) == To{}) + convertible_impl(from_kind, get_kind_tree_root(explode(to_kind).quantity))); + } else if constexpr (NestedQuantityKindSpecOf && get_kind_tree_root(To{}) == To{}) return yes; else if constexpr (NamedQuantitySpec && NamedQuantitySpec) { if constexpr (have_common_base(From{}, To{})) { @@ -1401,8 +1415,8 @@ template namespace detail { template - requires requires(Q q) { get_kind(q); } -using to_kind = std::remove_const_t; + requires requires(Q q) { get_kind_tree_root(q); } +using to_kind = std::remove_const_t; #ifdef __cpp_explicit_this_parameter template @@ -1415,19 +1429,8 @@ template return contains(); } -} // namespace detail - template -[[nodiscard]] consteval auto remove_kind(Q q) -{ - if constexpr (detail::QuantityKindSpec) - return Q::_quantity_spec_; - else - return q; -} - -template -[[nodiscard]] consteval QuantitySpec auto get_kind(Q q) +[[nodiscard]] consteval QuantitySpec auto get_kind_tree_root(Q q) { auto defined_as_kind = [](QQ qq) { if constexpr (requires { detail::defined_as_kind(qq); }) @@ -1441,7 +1444,7 @@ template } else if constexpr (defined_as_kind(Q{})) { return q; } else if constexpr (requires { Q::_parent_; }) { - return get_kind(Q::_parent_); + return get_kind_tree_root(Q::_parent_); } else if constexpr (detail::IntermediateDerivedQuantitySpec) { return detail::expr_map(q); @@ -1451,20 +1454,29 @@ template } } +} // namespace detail + +template +[[nodiscard]] consteval detail::QuantityKindSpec auto get_kind(Q q) +{ + return kind_of; +} + [[nodiscard]] consteval QuantitySpec auto common_quantity_spec(QuantitySpec auto q) { return q; } template [[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; - using QQ2 = std::remove_const_t; + using QQ1 = std::remove_const_t; + using QQ2 = std::remove_const_t; if constexpr (is_same_v) return q1; else if constexpr (detail::NestedQuantityKindSpecOf) - return remove_kind(q1); + return detail::remove_kind(q1); else if constexpr (detail::NestedQuantityKindSpecOf) - return remove_kind(q2); + return detail::remove_kind(q2); else if constexpr ((detail::QuantityKindSpec && !detail::QuantityKindSpec) || (detail::IntermediateDerivedQuantitySpec && detail::NamedQuantitySpec && implicitly_convertible(Q1{}, Q2{}))) @@ -1479,10 +1491,10 @@ template return q2; else if constexpr (implicitly_convertible(Q2{}, Q1{})) return q1; - else if constexpr (implicitly_convertible(get_kind(Q1{}), get_kind(Q2{}))) - return get_kind(q2); + else if constexpr (implicitly_convertible(get_kind_tree_root(Q1{}), get_kind_tree_root(Q2{}))) + return get_kind_tree_root(q2); else - return get_kind(q1); + return get_kind_tree_root(q1); } [[nodiscard]] consteval QuantitySpec auto common_quantity_spec(QuantitySpec auto q1, QuantitySpec auto q2, diff --git a/src/systems/include/mp-units/systems/iec80000/binary_prefixes.h b/src/systems/include/mp-units/systems/iec80000/binary_prefixes.h index ca3db21e..112e71a8 100644 --- a/src/systems/include/mp-units/systems/iec80000/binary_prefixes.h +++ b/src/systems/include/mp-units/systems/iec80000/binary_prefixes.h @@ -27,23 +27,23 @@ namespace mp_units::iec80000 { // clang-format off -template struct kibi_ : prefixed_unit<"Ki", mag_power<2, 10>, U> {}; -template struct mebi_ : prefixed_unit<"Mi", mag_power<2, 20>, U> {}; -template struct gibi_ : prefixed_unit<"Gi", mag_power<2, 30>, U> {}; -template struct tebi_ : prefixed_unit<"Ti", mag_power<2, 40>, U> {}; -template struct pebi_ : prefixed_unit<"Pi", mag_power<2, 50>, U> {}; -template struct exbi_ : prefixed_unit<"Ei", mag_power<2, 60>, U> {}; -template struct zebi_ : prefixed_unit<"Zi", mag_power<2, 70>, U> {}; -template struct yobi_ : prefixed_unit<"Yi", mag_power<2, 80>, U> {}; +template struct kibi_ : prefixed_unit<"Ki", mag_power<2, 10>, U{}> {}; +template struct mebi_ : prefixed_unit<"Mi", mag_power<2, 20>, U{}> {}; +template struct gibi_ : prefixed_unit<"Gi", mag_power<2, 30>, U{}> {}; +template struct tebi_ : prefixed_unit<"Ti", mag_power<2, 40>, U{}> {}; +template struct pebi_ : prefixed_unit<"Pi", mag_power<2, 50>, U{}> {}; +template struct exbi_ : prefixed_unit<"Ei", mag_power<2, 60>, U{}> {}; +template struct zebi_ : prefixed_unit<"Zi", mag_power<2, 70>, U{}> {}; +template struct yobi_ : prefixed_unit<"Yi", mag_power<2, 80>, U{}> {}; -template inline constexpr kibi_ kibi; -template inline constexpr mebi_ mebi; -template inline constexpr gibi_ gibi; -template inline constexpr tebi_ tebi; -template inline constexpr pebi_ pebi; -template inline constexpr exbi_ exbi; -template inline constexpr zebi_ zebi; -template inline constexpr yobi_ yobi; +template inline constexpr kibi_> kibi; +template inline constexpr mebi_> mebi; +template inline constexpr gibi_> gibi; +template inline constexpr tebi_> tebi; +template inline constexpr pebi_> pebi; +template inline constexpr exbi_> exbi; +template inline constexpr zebi_> zebi; +template inline constexpr yobi_> yobi; // clang-format on } // namespace mp_units::iec80000 diff --git a/src/systems/include/mp-units/systems/si/prefixes.h b/src/systems/include/mp-units/systems/si/prefixes.h index f8c9431c..09582df0 100644 --- a/src/systems/include/mp-units/systems/si/prefixes.h +++ b/src/systems/include/mp-units/systems/si/prefixes.h @@ -27,55 +27,55 @@ namespace mp_units::si { // clang-format off -template struct quecto_ : prefixed_unit<"q", mag_power<10, -30>, U> {}; -template struct ronto_ : prefixed_unit<"r", mag_power<10, -27>, U> {}; -template struct yocto_ : prefixed_unit<"y", mag_power<10, -24>, U> {}; -template struct zepto_ : prefixed_unit<"z", mag_power<10, -21>, U> {}; -template struct atto_ : prefixed_unit<"a", mag_power<10, -18>, U> {}; -template struct femto_ : prefixed_unit<"f", mag_power<10, -15>, U> {}; -template struct pico_ : prefixed_unit<"p", mag_power<10, -12>, U> {}; -template struct nano_ : prefixed_unit<"n", mag_power<10, -9>, U> {}; -template struct micro_ : prefixed_unit, U> {}; -template struct milli_ : prefixed_unit<"m", mag_power<10, -3>, U> {}; -template struct centi_ : prefixed_unit<"c", mag_power<10, -2>, U> {}; -template struct deci_ : prefixed_unit<"d", mag_power<10, -1>, U> {}; -template struct deca_ : prefixed_unit<"da", mag_power<10, 1>, U> {}; -template struct hecto_ : prefixed_unit<"h", mag_power<10, 2>, U> {}; -template struct kilo_ : prefixed_unit<"k", mag_power<10, 3>, U> {}; -template struct mega_ : prefixed_unit<"M", mag_power<10, 6>, U> {}; -template struct giga_ : prefixed_unit<"G", mag_power<10, 9>, U> {}; -template struct tera_ : prefixed_unit<"T", mag_power<10, 12>, U> {}; -template struct peta_ : prefixed_unit<"P", mag_power<10, 15>, U> {}; -template struct exa_ : prefixed_unit<"E", mag_power<10, 18>, U> {}; -template struct zetta_ : prefixed_unit<"Z", mag_power<10, 21>, U> {}; -template struct yotta_ : prefixed_unit<"Y", mag_power<10, 24>, U> {}; -template struct ronna_ : prefixed_unit<"R", mag_power<10, 27>, U> {}; -template struct quetta_ : prefixed_unit<"Q", mag_power<10, 30>, U> {}; +template struct quecto_ : prefixed_unit<"q", mag_power<10, -30>, U{}> {}; +template struct ronto_ : prefixed_unit<"r", mag_power<10, -27>, U{}> {}; +template struct yocto_ : prefixed_unit<"y", mag_power<10, -24>, U{}> {}; +template struct zepto_ : prefixed_unit<"z", mag_power<10, -21>, U{}> {}; +template struct atto_ : prefixed_unit<"a", mag_power<10, -18>, U{}> {}; +template struct femto_ : prefixed_unit<"f", mag_power<10, -15>, U{}> {}; +template struct pico_ : prefixed_unit<"p", mag_power<10, -12>, U{}> {}; +template struct nano_ : prefixed_unit<"n", mag_power<10, -9>, U{}> {}; +template struct micro_ : prefixed_unit, U{}> {}; +template struct milli_ : prefixed_unit<"m", mag_power<10, -3>, U{}> {}; +template struct centi_ : prefixed_unit<"c", mag_power<10, -2>, U{}> {}; +template struct deci_ : prefixed_unit<"d", mag_power<10, -1>, U{}> {}; +template struct deca_ : prefixed_unit<"da", mag_power<10, 1>, U{}> {}; +template struct hecto_ : prefixed_unit<"h", mag_power<10, 2>, U{}> {}; +template struct kilo_ : prefixed_unit<"k", mag_power<10, 3>, U{}> {}; +template struct mega_ : prefixed_unit<"M", mag_power<10, 6>, U{}> {}; +template struct giga_ : prefixed_unit<"G", mag_power<10, 9>, U{}> {}; +template struct tera_ : prefixed_unit<"T", mag_power<10, 12>, U{}> {}; +template struct peta_ : prefixed_unit<"P", mag_power<10, 15>, U{}> {}; +template struct exa_ : prefixed_unit<"E", mag_power<10, 18>, U{}> {}; +template struct zetta_ : prefixed_unit<"Z", mag_power<10, 21>, U{}> {}; +template struct yotta_ : prefixed_unit<"Y", mag_power<10, 24>, U{}> {}; +template struct ronna_ : prefixed_unit<"R", mag_power<10, 27>, U{}> {}; +template struct quetta_ : prefixed_unit<"Q", mag_power<10, 30>, U{}> {}; -template inline constexpr quecto_ quecto; -template inline constexpr ronto_ ronto; -template inline constexpr yocto_ yocto; -template inline constexpr zepto_ zepto; -template inline constexpr atto_ atto; -template inline constexpr femto_ femto; -template inline constexpr pico_ pico; -template inline constexpr nano_ nano; -template inline constexpr micro_ micro; -template inline constexpr milli_ milli; -template inline constexpr centi_ centi; -template inline constexpr deci_ deci; -template inline constexpr deca_ deca; -template inline constexpr hecto_ hecto; -template inline constexpr kilo_ kilo; -template inline constexpr mega_ mega; -template inline constexpr giga_ giga; -template inline constexpr tera_ tera; -template inline constexpr peta_ peta; -template inline constexpr exa_ exa; -template inline constexpr zetta_ zetta; -template inline constexpr yotta_ yotta; -template inline constexpr ronna_ ronna; -template inline constexpr quetta_ quetta; +template inline constexpr quecto_> quecto; +template inline constexpr ronto_> ronto; +template inline constexpr yocto_> yocto; +template inline constexpr zepto_> zepto; +template inline constexpr atto_> atto; +template inline constexpr femto_> femto; +template inline constexpr pico_> pico; +template inline constexpr nano_> nano; +template inline constexpr micro_> micro; +template inline constexpr milli_> milli; +template inline constexpr centi_> centi; +template inline constexpr deci_> deci; +template inline constexpr deca_> deca; +template inline constexpr hecto_> hecto; +template inline constexpr kilo_> kilo; +template inline constexpr mega_> mega; +template inline constexpr giga_> giga; +template inline constexpr tera_> tera; +template inline constexpr peta_> peta; +template inline constexpr exa_> exa; +template inline constexpr zetta_> zetta; +template inline constexpr yotta_> yotta; +template inline constexpr ronna_> ronna; +template inline constexpr quetta_> quetta; // clang-format on } // namespace mp_units::si diff --git a/test/runtime/CMakeLists.txt b/test/runtime/CMakeLists.txt index b22c7022..897957a9 100644 --- a/test/runtime/CMakeLists.txt +++ b/test/runtime/CMakeLists.txt @@ -24,7 +24,7 @@ cmake_minimum_required(VERSION 3.5) 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) target_compile_definitions(unit_tests_runtime PUBLIC ${projectPrefix}MODULES) endif() diff --git a/test/runtime/atomic_test.cpp b/test/runtime/atomic_test.cpp new file mode 100644 index 00000000..ba382edf --- /dev/null +++ b/test/runtime/atomic_test.cpp @@ -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 +#include +#include +#include +#include + +using namespace mp_units; +using namespace mp_units::si::unit_symbols; + +TEST_CASE("std::atomic works with dimensioned types", "[atomic][assignment]") +{ + std::atomic> a1 = 3.0 * isq::area[m2]; + std::atomic> a2 = 3.0 * isq::area[m2]; + REQUIRE(a1.load() == a2.load()); +} diff --git a/test/static/quantity_spec_test.cpp b/test/static/quantity_spec_test.cpp index d9713686..b845e4c8 100644 --- a/test/static/quantity_spec_test.cpp +++ b/test/static/quantity_spec_test.cpp @@ -396,25 +396,25 @@ static_assert(acceleration * (time * time) != position_vector); static_assert(acceleration / speed != frequency); // get_kind -static_assert(get_kind(length) == length); -static_assert(get_kind(distance) == length); -static_assert(get_kind(time) == time); -static_assert(get_kind(period_duration) == time); -static_assert(get_kind(length / time) == length / time); -static_assert(get_kind(speed) == speed); -static_assert(get_kind(height / time) == length / time); -static_assert(get_kind(inverse(time)) == inverse(time)); -static_assert(get_kind(inverse(period_duration)) == inverse(time)); -static_assert(get_kind(frequency) == frequency); -static_assert(get_kind(mass * frequency) == mass * frequency); -static_assert(get_kind(moment_of_force) == moment_of_force); -static_assert(get_kind(energy) == energy); -static_assert(get_kind(potential_energy) == energy); -static_assert(get_kind(kinetic_energy) == energy); -static_assert(get_kind(pow<1, 2>(area)) == pow<1, 2>(area)); -static_assert(get_kind(angular_measure) == angular_measure); -static_assert(get_kind(phase_angle) == angular_measure); -static_assert(get_kind(rotational_displacement) == angular_measure); +static_assert(get_kind(length) == kind_of); +static_assert(get_kind(distance) == kind_of); +static_assert(get_kind(time) == kind_of