diff --git a/.github/workflows/ci-conan.yml b/.github/workflows/ci-conan.yml index e7a66487..8825a9d1 100644 --- a/.github/workflows/ci-conan.yml +++ b/.github/workflows/ci-conan.yml @@ -116,18 +116,18 @@ jobs: lib: "libc++", conan-config: "", } - # - { - # name: "Apple Clang 13", - # os: macos-11, - # compiler: - # { - # type: APPLE_CLANG, - # version: "13.0", - # cc: "clang", - # cxx: "clang++", - # }, - # conan-config: "", - # } + - { + name: "Apple Clang 15", + os: macos-13, + compiler: + { + type: APPLE_CLANG, + version: "15.0", + cc: "clang", + cxx: "clang++", + }, + conan-config: "", + } build_type: ["Release", "Debug"] env: @@ -174,11 +174,11 @@ jobs: shell: bash run: | sudo apt install -y libc++-${{ matrix.config.compiler.version }}-dev libc++abi-${{ matrix.config.compiler.version }}-dev libunwind-${{ matrix.config.compiler.version }}-dev - - name: Select Xcode 13.0 - if: matrix.config.compiler.type == 'APPLE_CLANG' && matrix.config.compiler.version == '13.0' + - name: Select Xcode version + if: matrix.config.compiler.type == 'APPLE_CLANG' shell: bash run: | - sudo xcode-select -s "/Applications/Xcode_13.0.app" + sudo xcode-select -s /Applications/Xcode_${{ matrix.config.compiler.version }}.app && /usr/bin/xcodebuild -version - name: Install Ninja shell: bash run: | diff --git a/.github/workflows/ci-test-package-cmake.yml b/.github/workflows/ci-test-package-cmake.yml index acbadc38..a621125a 100644 --- a/.github/workflows/ci-test-package-cmake.yml +++ b/.github/workflows/ci-test-package-cmake.yml @@ -111,17 +111,18 @@ jobs: lib: "libc++", conan-config: "", } - # - { - # name: "Apple Clang 13", - # os: macos-11, - # compiler: - # { - # type: APPLE_CLANG, - # version: "13.0", - # cc: "clang", - # cxx: "clang++", - # }, - # } + - { + name: "Apple Clang 15", + os: macos-13, + compiler: + { + type: APPLE_CLANG, + version: "15.0", + cc: "clang", + cxx: "clang++", + }, + conan-config: "", + } build_type: ["Release", "Debug"] env: @@ -167,11 +168,11 @@ jobs: shell: bash run: | sudo apt install -y libc++-${{ matrix.config.compiler.version }}-dev libc++abi-${{ matrix.config.compiler.version }}-dev libunwind-${{ matrix.config.compiler.version }}-dev - - name: Select Xcode 13.0 - if: matrix.config.compiler.type == 'APPLE_CLANG' && matrix.config.compiler.version == '13.0' + - name: Select Xcode version + if: matrix.config.compiler.type == 'APPLE_CLANG' shell: bash run: | - sudo xcode-select -s "/Applications/Xcode_13.0.app" + sudo xcode-select -s /Applications/Xcode_${{ matrix.config.compiler.version }}.app && /usr/bin/xcodebuild -version - name: Install Ninja shell: bash run: | diff --git a/CHANGELOG.md b/CHANGELOG.md index d4e4f97b..5d632e7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,13 +2,19 @@ ## mp-units -### 2.1.0 WIP { id="2.1.0" } +### 2.2.0 WIP { id="2.2.0" } + + +### 2.1.0 December 9, 2023 { id="2.1.0" } - (!) feat: `inverse()` support added for dimensions, quantity_spec, units, and references (`1 / s` will now create `quantity` and not a `Unit`) - (!) feat: `quantity_point` does not provide `zero()` anymore - (!) feat: `quantity_spec` and its kind should not compare equal - (!) feat: mutating interface removed from `fixed_string` +- (!) feat: `common_type` with a raw value is not needed anymore as for a long time now raw values are + not convertible to the dimensionless quantities +- (!) feat: `symbol_text` definition simplified - feat: `basic_fixed_string(const CharT*, std::integral_constant)` constructor added - feat: `isq::activity` added and `becquerel` definition updated to benefit from it - feat: `gray` and `sievert` now have correct associated quantity kinds @@ -18,16 +24,42 @@ - feat: interoperability with other libraries redesigned - feat: equality for dimensions now will allow derived classes as well (but not from `derived_dimension`) - feat: `zero_Fahrenheit` point origin added +- feat: users are now allowed to inherit their ow types from absolute point origins +- feat: equivalent point origins handling improved +- feat(example): unit symbols added to the currency example - (!) refactor: `unit_symbol(U)` signature refactored and the resulting text can now also be used at runtime +- (!) refactor: `make_xxx` factory functions replaced with two-parameter constructors +- (!) refactor: `unit_symbol` changed to `consteval` - refactor: `in(U)` and `force_in(U)` now return `auto` to provide better diagnostics on clang +- refactor: `quantity` operators constraints refactored +- refactor: more type members added to `fixed_string` definition +- refactor: `unit_symbol_formatting` enums now use `std::int8_t` as a representation type - fix: symbols of named dimensionless units with the ratio = 1 were not printed - fix: iterator is now properly updated for all cases in `unit_symbol` - fix: Fahrenheit conversion ratio was inverted +- fix: `CommonlyInvocableQuantities` was overconstrained for the current library design +- fix: `are_ingredients_convertible` now mandates explicit conversion for `To` dimensionless quantities +- fix: `quantity_point::point_for(PO)` constraints fixed - fix(example): `latitude` and `longitude` fixed to include `0` for `N` and `E` respectively - ci: clang-17 enabled +- ci: apple-clang-15 enabled - ci: Added C++23 builds to the CI matrix +- docs: "Getting Started" chapters updated +- docs: "Basic Concepts" and "Interface Introduction" chapters updated +- docs: "Design Overview" chapter added and "Concepts" chapter reworked +- docs: "Output stream formatting" chapter updated +- docs: "Default formatting" chapter updated +- docs: "Derived unit symbols generation" chapter added +- docs: outdated affine space chapter updated - docs: `CameCase` concept identifiers FAQ added - docs: `gravitational_potential_energy` equation fixed on a graph +- docs: YouTube video link updated to the C++ on Sea 2023 +- docs: ISO papers reference added to docs and README +- docs: a representation type in a dimensionless quantity FAQ fixed +- docs: titles added to some important admonitions +- docs: "Terms and Definitions" slightly updated +- docs: "canonical unit" added to glossary and its documentation in code was updated +- docs: Design overview graph updated ### 2.0.0 September 24, 2023 { id="2.0.0" } diff --git a/README.md b/README.md index 6a5c783c..2bc55115 100644 --- a/README.md +++ b/README.md @@ -7,16 +7,16 @@ [![GitHub Workflow Documentation](https://img.shields.io/github/actions/workflow/status/mpusz/mp-units/documentation.yml?branch=master&label=Documentation)](https://github.com/mpusz/mp-units/actions?query=workflow%3ADocumentation+branch%3Amaster) [![Conan stable](https://img.shields.io/conan/v/mp-units?label=ConanCenter&color=blue)](https://conan.io/center/mp-units) -[![Conan testing](https://img.shields.io/badge/mpusz.jfrog.io-2.1.0%3Atesting-blue)](https://mpusz.jfrog.io/ui/packages/conan:%2F%2Fmp-units/2.1.0) +[![Conan testing](https://img.shields.io/badge/mpusz.jfrog.io-2.2.0%3Atesting-blue)](https://mpusz.jfrog.io/ui/packages/conan:%2F%2Fmp-units/2.2.0) -# `mp-units` - A Physical Quantities and Units library for C++ +# `mp-units` - A Quantities and Units library for C++ **The mp-units library might be the subject of ISO standardization for C++29. More on this can be found in the following ISO C++ proposals:** - [P1935: A C++ Approach to Physical Units](https://wg21.link/p1935), -- [P2980: A motivation, scope, and plan for a physical quantities and units library](https://wg21.link/p2980), +- [P2980: A motivation, scope, and plan for a quantities and units library](https://wg21.link/p2980), - [P2981: Improving our safety with a physical quantities and units library](https://wg21.link/p2981), - [P2982: `std::quantity` as a numeric type](https://wg21.link/p2982). diff --git a/conanfile.py b/conanfile.py index 9565ec1e..83098f97 100644 --- a/conanfile.py +++ b/conanfile.py @@ -36,7 +36,7 @@ required_conan_version = ">=2.0.0" class MPUnitsConan(ConanFile): name = "mp-units" homepage = "https://github.com/mpusz/mp-units" - description = "A Physical Quantities and Units library for C++" + description = "A Quantities and Units library for C++" topics = ( "units", "dimensions", @@ -74,8 +74,9 @@ class MPUnitsConan(ConanFile): def _minimum_compilers_version(self): return { "gcc": "11", - "clang": "16" - # , "apple-clang": "13", "msvc": "192" + "clang": "16", + "apple-clang": "15" + # , "msvc": "192" } @property diff --git a/docs/getting_started/installation_and_usage.md b/docs/getting_started/installation_and_usage.md index 51457786..164a652d 100644 --- a/docs/getting_started/installation_and_usage.md +++ b/docs/getting_started/installation_and_usage.md @@ -18,6 +18,7 @@ - please note that we observed some ICEs on gcc-11 - no problems with gcc-12.2+ - clang-16 + - apple-clang-15 ## Repository Structure and Dependencies @@ -283,7 +284,7 @@ The following steps may be performed to obtain an official library release: ```ini title="conanfile.txt" [requires] - mp-units/2.0.0 + mp-units/2.1.0 [layout] cmake_layout @@ -340,7 +341,7 @@ with the following differences: ```ini title="conanfile.txt" hl_lines="2" [requires] - mp-units/2.1.0@mpusz/testing + mp-units/2.2.0@mpusz/testing [layout] cmake_layout @@ -443,5 +444,5 @@ The above will create a Conan package and run tests provided in _./test_package_ ## Uploading **mp-units** Package to the Conan Server ```shell -conan upload -r --all mp-units/2.0.0@/ +conan upload -r --all mp-units/2.1.0@/ ``` diff --git a/docs/index.md b/docs/index.md index 3ced2ddb..7dec4ba6 100644 --- a/docs/index.md +++ b/docs/index.md @@ -37,3 +37,4 @@ The library source code is hosted on [GitHub](https://github.com/mpusz/mp-units) - please note that we observed some ICEs on gcc-11 - no problems with gcc-12.2+ - clang-16 + - apple-clang-15 diff --git a/docs/users_guide/framework_basics/the_affine_space.md b/docs/users_guide/framework_basics/the_affine_space.md index 608246f2..10fc026f 100644 --- a/docs/users_guide/framework_basics/the_affine_space.md +++ b/docs/users_guide/framework_basics/the_affine_space.md @@ -2,8 +2,8 @@ The affine space has two types of entities: -- **_point_** - a position specified with coordinate values (e.g. location, address, etc.) -- **_vector_** - the difference between two points (e.g. shift, offset, displacement, duration, etc.) +- **_point_** - a position specified with coordinate values (e.g., location, address, etc.) +- **_vector_** - the difference between two points (e.g., shift, offset, displacement, duration, etc.) !!! note @@ -38,16 +38,33 @@ Here are the primary operations one can do in the affine space: - multiply nor divide _points_ with anything else. +## _Points_ are more common than most of us imagine + +_Point_ abstractions should be used more often in the C++ software. +They are not only about temperature or time. _Points_ are everywhere around us and should become +more popular in the products we implement. They can be used to implement: + +- temperature points, +- timestamps, +- daily mass readouts from the scale, +- altitudes of mountain peaks on a map, +- current speed displayed on a car's speed-o-meter, +- today's price of instruments on the market, +- and many more. + +Improving the affine space's _points_ intuition will allow us to write better and safer software. + + ## _Vector_ is modeled by `quantity` -Up until now, each time when we used a `quantity` in our code, we were modeling some kind of a +Up until now, each time we used a `quantity` in our code, we were modeling some kind of a difference between two things: -- the distance between two points -- duration between two time points -- the difference in speed (even if relative to `0`) +- the distance between two points, +- duration between two time points, +- the difference in speed (even if relative to zero). -As we already know, a `quantity` type provides all operations required for _vector_ type in +As we already know, a `quantity` type provides all operations required for a _vector_ type in the affine space. @@ -327,7 +344,7 @@ The following operations are not allowed in the affine space: - **adding** two `quantity_point` objects - It is physically impossible to add positions of home and Denver airports. - **subtracting** a `quantity_point` from a `quantity` - - What would it mean to subtract DEN airport location from the distance to it? + - What would it mean to subtract the DEN airport location from the distance to it? - **multiplying/dividing** a `quantity_point` with a scalar - What is the position of `2 *` DEN airport location? - **multiplying/dividing** a `quantity_point` with a quantity @@ -337,13 +354,13 @@ The following operations are not allowed in the affine space: - **mixing** `quantity_points` of different quantity kinds - It is physically impossible to subtract time from length. - **mixing** `quantity_points` of inconvertible quantities - - What does it mean to subtract a distance point to DEN airport from the Mount Everest base camp - altitude? + - What does subtracting a distance point to DEN airport from the Mount Everest base camp + altitude mean? - **mixing** `quantity_points` of convertible quantities but with unrelated origins - - How to subtract a point on our trip to CppCon measured relatively to our home location from + - How do we subtract a point on our trip to CppCon measured relatively to our home location from a point measured relative to the center of the Solar System? !!! important "Important: The affine space improves safety" - The usage of `quantity_point` and affine space types in general, improves expressiveness and + The usage of `quantity_point` and affine space types, in general, improves expressiveness and type-safety of the code we write. diff --git a/example/include/geographic.h b/example/include/geographic.h index a647459a..0ccda628 100644 --- a/example/include/geographic.h +++ b/example/include/geographic.h @@ -66,7 +66,8 @@ namespace geographic { inline constexpr struct equator : mp_units::absolute_point_origin { } equator; -inline constexpr struct prime_meridian : mp_units::absolute_point_origin { +inline constexpr struct prime_meridian : + mp_units::absolute_point_origin { } prime_meridian; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4c7027a4..739e553e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -21,7 +21,7 @@ # SOFTWARE. cmake_minimum_required(VERSION 3.19) -project(mp-units VERSION 2.1.0 LANGUAGES CXX) +project(mp-units VERSION 2.2.0 LANGUAGES CXX) set(projectPrefix MP_UNITS_) diff --git a/src/utility/include/mp-units/math.h b/src/utility/include/mp-units/math.h index c613fea3..ab04e2a3 100644 --- a/src/utility/include/mp-units/math.h +++ b/src/utility/include/mp-units/math.h @@ -144,19 +144,31 @@ template * @param b: Addend * @return Quantity: The nearest floating point representable to ax+b */ -template -[[nodiscard]] constexpr quantity fma(const quantity& a, const quantity& x, - const quantity& b) noexcept + +template +[[nodiscard]] constexpr QuantityOf auto +fma( // QuantityOf takes a QuantitySpec as an argument + const quantity& a, const quantity& x, const quantity& b) noexcept requires requires { - fma(a.numerical_value_ref_in(a.unit), x.numerical_value_ref_in(x.unit), b.numerical_value_ref_in(b.unit)); - } || requires { - std::fma(a.numerical_value_ref_in(a.unit), x.numerical_value_ref_in(x.unit), b.numerical_value_ref_in(b.unit)); - } + common_quantity_spec(get_quantity_spec(R) * get_quantity_spec(S), get_quantity_spec(T)); + } && // or just common_reference but I wanted to express that the quantity types must match here and we don't care + // too much about units + (get_unit(R) * get_unit(S) == + get_unit(T)) && // units that we want to add are equivalent (have the same magnitude) + ( + requires { + fma(a.numerical_value_ref_in(a.unit), x.numerical_value_ref_in(x.unit), + b.numerical_value_ref_in(b.unit)); + } || + requires { + std::fma(a.numerical_value_ref_in(a.unit), x.numerical_value_ref_in(x.unit), + b.numerical_value_ref_in(b.unit)); + }) { using std::fma; - return {static_cast( - fma(a.numerical_value_ref_in(a.unit), x.numerical_value_ref_in(x.unit), b.numerical_value_ref_in(b.unit))), - R}; + return quantity{ + fma(a.numerical_value_ref_in(a.unit), x.numerical_value_ref_in(x.unit), b.numerical_value_ref_in(b.unit)), T}; } diff --git a/test/unit_test/runtime/math_test.cpp b/test/unit_test/runtime/math_test.cpp index d7518de7..1726f7c1 100644 --- a/test/unit_test/runtime/math_test.cpp +++ b/test/unit_test/runtime/math_test.cpp @@ -62,9 +62,9 @@ TEST_CASE("'cbrt()' on quantity changes the value and the dimension accordingly" REQUIRE(cbrt(8 * isq::volume[m3]) == 2 * isq::length[m]); } -TEST_CASE("'fma()' on quantity changes the value and the dimension accordingly", "[math][cbrt]") +TEST_CASE("'fma()' on quantity changes the value and the dimension accordingly", "[math][fma]") { - REQUIRE(fma(1.0 * isq::length[m], 2.0, 2.0 * isq::length[m]) == 4.0 * isq::length[m]); + REQUIRE(fma(1.0 * isq::length[m], 2.0 * one, 2.0 * isq::length[m]) == 4.0 * isq::length[m]); } diff --git a/test/unit_test/static/math_test.cpp b/test/unit_test/static/math_test.cpp index 7d877927..4874aabb 100644 --- a/test/unit_test/static/math_test.cpp +++ b/test/unit_test/static/math_test.cpp @@ -40,11 +40,10 @@ template #if __cpp_lib_constexpr_cmath || MP_UNITS_COMP_GCC -static_assert(compare(fma(2 * m, 3 * m, 1 * m2), 7 * m2)); -static_assert(compare(fma(2.0 * s, 3.0 * Hz, 1.0), 7.0)); -static_assert(compare(fma(2 * s, 3 * Hz, 1), 7)); -static_assert(compare(fma(2.0, 3.0*m, 1.0*m), 7*m); -static_assert(compare(fma(2.0*m, 3.0, 1.0*m), 7*m)); +static_assert(compare(fma(2.0 * s, 3.0 * Hz, 1.0 * one), 7.0 * one)); +static_assert(compare(fma(2.0 * one, 3.0 * m, 1.0 * m), 7.0 * m)); +static_assert(compare(fma(2.0 * m, 3.0 * one, 1.0 * m), 7.0 * m)); +static_assert(compare(fma(2 * m, 3.0f * m, 1.0 * m2), 7.0 * m2)); static_assert(compare(pow<0>(2 * m), 1 * one)); static_assert(compare(pow<1>(2 * m), 2 * m)); static_assert(compare(pow<2>(2 * m), 4 * pow<2>(m), 4 * m2));