mirror of
https://github.com/mpusz/mp-units.git
synced 2025-06-25 01:01:33 +02:00
Merge branch 'master' into feature/more-value-casts
This commit is contained in:
138
.github/workflows/ci-clang-tidy.yml
vendored
Normal file
138
.github/workflows/ci-clang-tidy.yml
vendored
Normal file
@ -0,0 +1,138 @@
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2018 Mateusz Pusz
|
||||
#
|
||||
# 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.
|
||||
|
||||
name: clang-tidy CI
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- "docs/**"
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "docs/**"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: "${{ matrix.formatting }} ${{ matrix.contracts }} C++${{ matrix.std }} ${{ matrix.config.name }} ${{ matrix.build_type }}"
|
||||
runs-on: ${{ matrix.config.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
formatting: ["std::format", "fmtlib"]
|
||||
contracts: ["none", "gsl-lite", "ms-gsl"]
|
||||
std: [20, 23]
|
||||
config:
|
||||
- {
|
||||
name: "Clang-18",
|
||||
os: ubuntu-24.04,
|
||||
compiler:
|
||||
{
|
||||
type: CLANG,
|
||||
version: 18,
|
||||
cc: "clang-18",
|
||||
cxx: "clang++-18",
|
||||
},
|
||||
lib: "libc++",
|
||||
cxx_modules: "False",
|
||||
std_format_support: "True",
|
||||
conan-config: "",
|
||||
}
|
||||
build_type: ["Release", "Debug"]
|
||||
|
||||
env:
|
||||
CC: ${{ matrix.config.compiler.cc }}
|
||||
CXX: ${{ matrix.config.compiler.cxx }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: echo "cache_id=$(/bin/date -u "+%Y%m%d")" >> $GITHUB_ENV
|
||||
- name: Cache Conan data
|
||||
uses: actions/cache@v4
|
||||
if: always()
|
||||
env:
|
||||
cache-name: cache-conan-data
|
||||
with:
|
||||
path: ~/.conan2/p
|
||||
key: clang-tidy-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-${{ matrix.std }}-${{ env.cache_id }}
|
||||
restore-keys: |
|
||||
clang-tidy-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-${{ matrix.std }}-
|
||||
clang-tidy-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-
|
||||
clang-tidy-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-
|
||||
clang-tidy-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-
|
||||
clang-tidy-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-
|
||||
clang-tidy-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-
|
||||
clang-tidy-${{ matrix.config.os }}-${{ matrix.formatting }}-
|
||||
clang-tidy-${{ matrix.config.os }}-
|
||||
- uses: hendrikmuhs/ccache-action@v1.2
|
||||
if: runner.os == 'Linux'
|
||||
with:
|
||||
key: ${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-${{ matrix.std }}
|
||||
max-size: 50M
|
||||
- name: Install Clang
|
||||
if: matrix.config.compiler.type == 'CLANG'
|
||||
shell: bash
|
||||
working-directory: ${{ env.HOME }}
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh ${{ matrix.config.compiler.version }}
|
||||
sudo apt install -y clang-tools-${{ matrix.config.compiler.version }}
|
||||
- name: Install Libc++
|
||||
if: matrix.config.compiler.type == 'CLANG' && matrix.config.lib == 'libc++'
|
||||
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: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.x
|
||||
- name: Install Ninja
|
||||
shell: bash
|
||||
run: |
|
||||
pip install -U ninja
|
||||
- name: Install Conan
|
||||
shell: bash
|
||||
run: |
|
||||
pip install -U conan
|
||||
- name: Configure Conan
|
||||
shell: bash
|
||||
run: |
|
||||
conan profile detect --force
|
||||
if [[ "${{ matrix.config.compiler.type }}" == "CLANG" ]]; then
|
||||
sed -i.backup '/^\[settings\]$/,/^\[/ s/^compiler.libcxx=.*/compiler.libcxx=${{ matrix.config.lib }}/' ~/.conan2/profiles/default
|
||||
fi
|
||||
sed -i.backup '/^\[settings\]$/,/^\[/ s/^compiler.cppstd=.*/compiler.cppstd=${{ matrix.std }}/' ~/.conan2/profiles/default
|
||||
sed -i.backup '/^\[settings\]$/,/^\[/ s/^build_type=.*/build_type=${{ matrix.build_type }}/' ~/.conan2/profiles/default
|
||||
conan profile show -pr default
|
||||
- run: echo "std_format=$([ "${{ matrix.formatting }}" == "std::format" ] && echo "True" || echo "False")" >> $GITHUB_ENV
|
||||
- name: Run clang-tidy
|
||||
shell: bash
|
||||
run: |
|
||||
conan build . -b missing -c tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" \
|
||||
-c user.mp-units.build:all=True -c user.mp-units.analyze:clang-tidy=True \
|
||||
-o cxx_modules=${{ matrix.config.cxx_modules }} -o std_format=${{ env.std_format }} -o contracts=${{ matrix.contracts }} ${{ matrix.config.conan-config }}
|
||||
- name: Clean Conan cache before backup
|
||||
shell: bash
|
||||
run: |
|
||||
conan remove *#~latest --confirm
|
||||
conan remove *:*#~latest --confirm
|
||||
conan cache clean "*" -s -b -d
|
52
.github/workflows/ci-conan.yml
vendored
52
.github/workflows/ci-conan.yml
vendored
@ -35,12 +35,13 @@ env:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: "${{ matrix.formatting }} C++${{ matrix.std }} ${{ matrix.config.name }} ${{ matrix.build_type }}"
|
||||
name: "${{ matrix.formatting }} ${{ matrix.contracts }} C++${{ matrix.std }} ${{ matrix.config.name }} ${{ matrix.build_type }}"
|
||||
runs-on: ${{ matrix.config.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
formatting: ["std::format", "fmtlib"]
|
||||
contracts: ["none", "gsl-lite", "ms-gsl"]
|
||||
std: [20, 23]
|
||||
config:
|
||||
# - {
|
||||
@ -57,7 +58,7 @@ jobs:
|
||||
# }
|
||||
- {
|
||||
name: "GCC-12",
|
||||
os: ubuntu-22.04,
|
||||
os: ubuntu-24.04,
|
||||
compiler:
|
||||
{
|
||||
type: GCC,
|
||||
@ -71,7 +72,7 @@ jobs:
|
||||
}
|
||||
- {
|
||||
name: "GCC-13",
|
||||
os: ubuntu-22.04,
|
||||
os: ubuntu-24.04,
|
||||
compiler:
|
||||
{
|
||||
type: GCC,
|
||||
@ -83,6 +84,20 @@ jobs:
|
||||
std_format_support: "True",
|
||||
conan-config: "",
|
||||
}
|
||||
- {
|
||||
name: "GCC-14",
|
||||
os: ubuntu-24.04,
|
||||
compiler:
|
||||
{
|
||||
type: GCC,
|
||||
version: 14,
|
||||
cc: "gcc-14",
|
||||
cxx: "g++-14",
|
||||
},
|
||||
cxx_modules: "False",
|
||||
std_format_support: "True",
|
||||
conan-config: "",
|
||||
}
|
||||
- {
|
||||
name: "Clang-16",
|
||||
os: ubuntu-22.04,
|
||||
@ -100,7 +115,7 @@ jobs:
|
||||
}
|
||||
- {
|
||||
name: "Clang-17",
|
||||
os: ubuntu-22.04,
|
||||
os: ubuntu-24.04,
|
||||
compiler:
|
||||
{
|
||||
type: CLANG,
|
||||
@ -115,7 +130,7 @@ jobs:
|
||||
}
|
||||
- {
|
||||
name: "Clang-18",
|
||||
os: ubuntu-22.04,
|
||||
os: ubuntu-24.04,
|
||||
compiler:
|
||||
{
|
||||
type: CLANG,
|
||||
@ -161,19 +176,20 @@ jobs:
|
||||
cache-name: cache-conan-data
|
||||
with:
|
||||
path: ~/.conan2/p
|
||||
key: conan-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-${{ matrix.std }}-${{ env.cache_id }}
|
||||
key: conan-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-${{ matrix.std }}-${{ env.cache_id }}
|
||||
restore-keys: |
|
||||
conan-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-${{ matrix.std }}-
|
||||
conan-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-
|
||||
conan-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-
|
||||
conan-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-
|
||||
conan-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.config.compiler.type }}-
|
||||
conan-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-${{ matrix.std }}-
|
||||
conan-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-
|
||||
conan-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-
|
||||
conan-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-
|
||||
conan-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-
|
||||
conan-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-
|
||||
conan-${{ matrix.config.os }}-${{ matrix.formatting }}-
|
||||
conan-${{ matrix.config.os }}-
|
||||
- uses: hendrikmuhs/ccache-action@v1.2
|
||||
if: runner.os == 'Linux'
|
||||
with:
|
||||
key: ${{ matrix.config.os }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-${{ matrix.std }}
|
||||
key: ${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-${{ matrix.std }}
|
||||
max-size: 50M
|
||||
- name: Install gcc-13
|
||||
if: matrix.config.compiler.type == 'GCC' && matrix.config.compiler.version == '13'
|
||||
@ -202,7 +218,7 @@ jobs:
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.8"
|
||||
python-version: 3.x
|
||||
- name: Install Ninja
|
||||
shell: bash
|
||||
run: |
|
||||
@ -227,7 +243,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.mp-units.build:all=True -o cxx_modules=${{ matrix.config.cxx_modules }} -o std_format=${{ env.std_format }} ${{ matrix.config.conan-config }}
|
||||
-c user.mp-units.build:all=True -o cxx_modules=${{ matrix.config.cxx_modules }} -o std_format=${{ env.std_format }} -o contracts=${{ matrix.contracts }} ${{ matrix.config.conan-config }}
|
||||
- name: Obtain package reference
|
||||
id: get-package-ref
|
||||
shell: bash
|
||||
@ -244,8 +260,8 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
conan remove mp-units --confirm
|
||||
conan remove *#!latest --confirm
|
||||
conan remove *:*#!latest --confirm
|
||||
conan remove *#~latest --confirm
|
||||
conan remove *:*#~latest --confirm
|
||||
conan cache clean "*" -s -b -d
|
||||
outputs:
|
||||
package_ref: ${{ steps.get-package-ref.outputs.PACKAGE_REF }}
|
||||
@ -254,13 +270,13 @@ jobs:
|
||||
if: github.ref == 'refs/heads/master' || (github.ref_type == 'tag' && startsWith(github.ref_name, 'v'))
|
||||
needs: build
|
||||
name: Promote Conan package
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.8"
|
||||
python-version: 3.x
|
||||
- name: Install Conan
|
||||
shell: bash
|
||||
run: |
|
||||
|
6
.github/workflows/ci-formatting.yml
vendored
6
.github/workflows/ci-formatting.yml
vendored
@ -26,13 +26,13 @@ on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
check:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python 3.8
|
||||
- name: Set up Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.8
|
||||
python-version: 3.x
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
|
156
.github/workflows/ci-freestanding.yml
vendored
Normal file
156
.github/workflows/ci-freestanding.yml
vendored
Normal file
@ -0,0 +1,156 @@
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2018 Mateusz Pusz
|
||||
#
|
||||
# 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.
|
||||
|
||||
name: Freestanding CI
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- "docs/**"
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "docs/**"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: "${{ matrix.formatting }} ${{ matrix.contracts }} C++${{ matrix.std }} ${{ matrix.config.name }} ${{ matrix.build_type }}"
|
||||
runs-on: ${{ matrix.config.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
formatting: ["std::format", "fmtlib"]
|
||||
contracts: ["none"]
|
||||
std: [23]
|
||||
config:
|
||||
- {
|
||||
name: "GCC-14",
|
||||
os: ubuntu-24.04,
|
||||
compiler:
|
||||
{
|
||||
type: GCC,
|
||||
version: 14,
|
||||
cc: "gcc-14",
|
||||
cxx: "g++-14",
|
||||
},
|
||||
cxx_modules: "False",
|
||||
std_format_support: "True",
|
||||
conan-config: "",
|
||||
}
|
||||
- {
|
||||
name: "Clang-18",
|
||||
os: ubuntu-24.04,
|
||||
compiler:
|
||||
{
|
||||
type: CLANG,
|
||||
version: 18,
|
||||
cc: "clang-18",
|
||||
cxx: "clang++-18",
|
||||
},
|
||||
lib: "libc++",
|
||||
cxx_modules: "True",
|
||||
std_format_support: "True",
|
||||
conan-config: "",
|
||||
}
|
||||
build_type: ["Release", "Debug"]
|
||||
# TODO For some reason Clang-18 Debug with -ffreestanding does not pass CMakeTestCXXCompiler
|
||||
exclude:
|
||||
- build_type: "Debug"
|
||||
config: { name: "Clang-18" }
|
||||
|
||||
env:
|
||||
CC: ${{ matrix.config.compiler.cc }}
|
||||
CXX: ${{ matrix.config.compiler.cxx }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: echo "cache_id=$(/bin/date -u "+%Y%m%d")" >> $GITHUB_ENV
|
||||
- name: Cache Conan data
|
||||
uses: actions/cache@v4
|
||||
if: always()
|
||||
env:
|
||||
cache-name: cache-conan-data
|
||||
with:
|
||||
path: ~/.conan2/p
|
||||
key: freestanding-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-${{ matrix.std }}-${{ env.cache_id }}
|
||||
restore-keys: |
|
||||
freestanding-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-${{ matrix.std }}-
|
||||
freestanding-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-
|
||||
freestanding-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-
|
||||
freestanding-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-
|
||||
freestanding-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-
|
||||
freestanding-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-
|
||||
freestanding-${{ matrix.config.os }}-${{ matrix.formatting }}-
|
||||
freestanding-${{ matrix.config.os }}-
|
||||
- uses: hendrikmuhs/ccache-action@v1.2
|
||||
if: runner.os == 'Linux'
|
||||
with:
|
||||
key: ${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-${{ matrix.std }}
|
||||
max-size: 50M
|
||||
- name: Install Clang
|
||||
if: matrix.config.compiler.type == 'CLANG'
|
||||
shell: bash
|
||||
working-directory: ${{ env.HOME }}
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh ${{ matrix.config.compiler.version }}
|
||||
sudo apt install -y clang-tools-${{ matrix.config.compiler.version }}
|
||||
- name: Install Libc++
|
||||
if: matrix.config.compiler.type == 'CLANG' && matrix.config.lib == 'libc++'
|
||||
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: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.x
|
||||
- name: Install Ninja
|
||||
shell: bash
|
||||
run: |
|
||||
pip install -U ninja
|
||||
- name: Install Conan
|
||||
shell: bash
|
||||
run: |
|
||||
pip install -U conan
|
||||
- name: Configure Conan
|
||||
shell: bash
|
||||
run: |
|
||||
conan profile detect --force
|
||||
if [[ "${{ matrix.config.compiler.type }}" == "CLANG" ]]; then
|
||||
sed -i.backup '/^\[settings\]$/,/^\[/ s/^compiler.libcxx=.*/compiler.libcxx=${{ matrix.config.lib }}/' ~/.conan2/profiles/default
|
||||
fi
|
||||
sed -i.backup '/^\[settings\]$/,/^\[/ s/^compiler.cppstd=.*/compiler.cppstd=${{ matrix.std }}/' ~/.conan2/profiles/default
|
||||
sed -i.backup '/^\[settings\]$/,/^\[/ s/^build_type=.*/build_type=${{ matrix.build_type }}/' ~/.conan2/profiles/default
|
||||
conan profile show -pr default
|
||||
- run: echo "std_format=$([ "${{ matrix.formatting }}" == "std::format" ] && echo "True" || echo "False")" >> $GITHUB_ENV
|
||||
- name: Build freestanding
|
||||
shell: bash
|
||||
run: |
|
||||
conan build . -b missing -c tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" \
|
||||
-c user.mp-units.build:all=True -c tools.build:cxxflags="['-ffreestanding']" \
|
||||
-o cxx_modules=${{ matrix.config.cxx_modules }} -o std_format=${{ env.std_format }} -o contracts=${{ matrix.contracts }} -o freestanding=True ${{ matrix.config.conan-config }}
|
||||
- name: Clean Conan cache before backup
|
||||
shell: bash
|
||||
run: |
|
||||
conan remove *#~latest --confirm
|
||||
conan remove *:*#~latest --confirm
|
||||
conan cache clean "*" -s -b -d
|
51
.github/workflows/ci-test-package-cmake.yml
vendored
51
.github/workflows/ci-test-package-cmake.yml
vendored
@ -36,12 +36,13 @@ on:
|
||||
|
||||
jobs:
|
||||
test_package:
|
||||
name: "${{ matrix.formatting }} C++${{ matrix.std }} ${{ matrix.config.name }} ${{ matrix.build_type }}"
|
||||
name: "${{ matrix.formatting }} ${{ matrix.contracts }} C++${{ matrix.std }} ${{ matrix.config.name }} ${{ matrix.build_type }}"
|
||||
runs-on: ${{ matrix.config.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
formatting: ["std::format", "fmtlib"]
|
||||
contracts: ["none", "gsl-lite", "ms-gsl"]
|
||||
std: [20, 23]
|
||||
config:
|
||||
# - {
|
||||
@ -56,7 +57,7 @@ jobs:
|
||||
# }
|
||||
- {
|
||||
name: "GCC-12",
|
||||
os: ubuntu-22.04,
|
||||
os: ubuntu-24.04,
|
||||
compiler:
|
||||
{
|
||||
type: GCC,
|
||||
@ -69,7 +70,7 @@ jobs:
|
||||
}
|
||||
- {
|
||||
name: "GCC-13",
|
||||
os: ubuntu-22.04,
|
||||
os: ubuntu-24.04,
|
||||
compiler:
|
||||
{
|
||||
type: GCC,
|
||||
@ -80,6 +81,19 @@ jobs:
|
||||
cxx_modules: "False",
|
||||
std_format_support: "True",
|
||||
}
|
||||
- {
|
||||
name: "GCC-14",
|
||||
os: ubuntu-24.04,
|
||||
compiler:
|
||||
{
|
||||
type: GCC,
|
||||
version: 14,
|
||||
cc: "gcc-14",
|
||||
cxx: "g++-14",
|
||||
},
|
||||
cxx_modules: "False",
|
||||
std_format_support: "True"
|
||||
}
|
||||
- {
|
||||
name: "Clang-16",
|
||||
os: ubuntu-22.04,
|
||||
@ -96,7 +110,7 @@ jobs:
|
||||
}
|
||||
- {
|
||||
name: "Clang-17",
|
||||
os: ubuntu-22.04,
|
||||
os: ubuntu-24.04,
|
||||
compiler:
|
||||
{
|
||||
type: CLANG,
|
||||
@ -110,7 +124,7 @@ jobs:
|
||||
}
|
||||
- {
|
||||
name: "Clang-18",
|
||||
os: ubuntu-22.04,
|
||||
os: ubuntu-24.04,
|
||||
compiler:
|
||||
{
|
||||
type: CLANG,
|
||||
@ -124,7 +138,7 @@ jobs:
|
||||
}
|
||||
- {
|
||||
name: "Apple Clang 15",
|
||||
os: macos-13,
|
||||
os: macos-14,
|
||||
compiler:
|
||||
{
|
||||
type: APPLE_CLANG,
|
||||
@ -147,7 +161,7 @@ jobs:
|
||||
steps:
|
||||
- name: Downcase 'build_type'
|
||||
id: build_type
|
||||
uses: ASzc/change-string-case-action@v5
|
||||
uses: ASzc/change-string-case-action@v6
|
||||
with:
|
||||
string: ${{ matrix.build_type }}
|
||||
- uses: actions/checkout@v4
|
||||
@ -159,13 +173,14 @@ jobs:
|
||||
cache-name: cache-conan-data
|
||||
with:
|
||||
path: ~/.conan2/p
|
||||
key: cmake-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-${{ matrix.std }}-${{ env.cache_id }}
|
||||
key: cmake-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-${{ matrix.std }}-${{ env.cache_id }}
|
||||
restore-keys: |
|
||||
cmake-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-${{ matrix.std }}-
|
||||
cmake-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-
|
||||
cmake-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-
|
||||
cmake-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-
|
||||
cmake-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.config.compiler.type }}-
|
||||
cmake-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-${{ matrix.std }}-
|
||||
cmake-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-
|
||||
cmake-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-
|
||||
cmake-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-
|
||||
cmake-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-
|
||||
cmake-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-
|
||||
cmake-${{ matrix.config.os }}-${{ matrix.formatting }}-
|
||||
cmake-${{ matrix.config.os }}-
|
||||
- name: Install gcc-13
|
||||
@ -195,7 +210,7 @@ jobs:
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.8"
|
||||
python-version: 3.x
|
||||
- name: Install Ninja
|
||||
shell: bash
|
||||
run: |
|
||||
@ -220,7 +235,7 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
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 std_format=${{ env.std_format }}
|
||||
-o cxx_modules=${{ matrix.config.cxx_modules }} -o std_format=${{ env.std_format }} -o contracts=${{ matrix.contracts }}
|
||||
- name: Provide dependencies for the build
|
||||
shell: bash
|
||||
working-directory: src
|
||||
@ -291,3 +306,9 @@ jobs:
|
||||
working-directory: test_package/build/install/${{ matrix.build_type }}
|
||||
run: |
|
||||
./test_package
|
||||
- name: Clean Conan cache before backup
|
||||
shell: bash
|
||||
run: |
|
||||
conan remove *#~latest --confirm
|
||||
conan remove *:*#~latest --confirm
|
||||
conan cache clean "*" -s -b -d
|
||||
|
8
.github/workflows/codeql.yml
vendored
8
.github/workflows/codeql.yml
vendored
@ -59,7 +59,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
@ -74,7 +74,7 @@ jobs:
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
if: matrix.language != 'cpp'
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
@ -97,7 +97,7 @@ jobs:
|
||||
if: matrix.language == 'cpp'
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.8"
|
||||
python-version: 3.x
|
||||
- name: Conan build
|
||||
if: matrix.language == 'cpp'
|
||||
run: |
|
||||
@ -108,6 +108,6 @@ jobs:
|
||||
conan build .. -s compiler.cppstd=20 -c user.mp-units.build:all=True -o std_format=False -b missing
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
uses: github/codeql-action/analyze@v3
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
|
40
CHANGELOG.md
40
CHANGELOG.md
@ -8,15 +8,18 @@
|
||||
- (!) feat: formatting grammar improved and units formatting support added
|
||||
- (!) feat: `has_unit_symbol` support removed
|
||||
- (!) feat: ABI concerns resolved with introduction of u8 strings for symbols
|
||||
- (!) feat: API-related Conan, CMake, and preprocessor options redesigned
|
||||
- (!) feat: :boom: `core.h` removed
|
||||
- feat: implicit point origins support added
|
||||
- feat: unit default point origin support added
|
||||
- feat: `fma`, `isfinite`, `isinf`, and `isnan` math function added by [@NAThompson](https://github.com/NAThompson)
|
||||
- feat: `fma` for quantity points added
|
||||
- feat: `quantity_point` support added for `quantity_cast` and `value_cast`
|
||||
- feat: `value_cast<Unit, Representation>` added
|
||||
- feat: `value_cast<Quantity>(q)`, `value_cast<Quantity>(qp)` and `value_cast<QuantityPoint>(qp)` added by [@burnpanck](https://github.com/burnpanck)
|
||||
- feat: `interconvertible(QuantitySpec, QuantitySpec)` added
|
||||
- feat: `qp.quantity_from_zero()` added
|
||||
- feat: `underlying_type` type trait added
|
||||
- feat: `value_type` type trait added
|
||||
- feat: do not print space between a number and `percent` or `per_mille`
|
||||
- feat: `ppm` parts per million added by [@nebkat](https://github.com/nebkat)
|
||||
- feat: `atan2` 2-argument arctangent added by [@nebkat](https://github.com/nebkat)
|
||||
@ -26,6 +29,10 @@
|
||||
- feat: unit text output support added
|
||||
- feat: formatting error messages improved
|
||||
- feat: improve types readability by eliminating extraneous `()` in references, prefixes, and `kind_of`
|
||||
- feat: dimension text output added
|
||||
- feat: some light and radiation ISQ quantities added
|
||||
- feat: New formatting specification implemented
|
||||
- feat: allow configuring GSL library use
|
||||
- (!) refactor: `zero_Fahrenheit` renamed to `zeroth_degree_Fahrenheit`
|
||||
- (!) refactor: SI-related trigonometric functions moved to the `si` subnamespace
|
||||
- (!) refactor: `math.h` header file broke up to smaller pieces
|
||||
@ -33,15 +40,28 @@
|
||||
- (!) refactor: `ReferenceOf` does not take a dimension anymore
|
||||
- (!) refactor: 'o' replaced with '1' as a modifier for `unit_symbol_solidus::one_denominator`
|
||||
- (!) refactor: `get_kind()` now returns `kind_of`
|
||||
- (!) refactor: FMT macros moved to `compat_macros.h`
|
||||
- (!) refactor: `fixed_string` refactored to reflect the latest changes to [P3094R2](https://wg21.link/P3094R2)
|
||||
- (!) refactor: `basic_symbol_text` renamed to `symbol_text`
|
||||
- (!) refactor: `ratio` hidden as an implementation detail behind `mag_ratio`
|
||||
- (!) refactor: `framework.h` introduced
|
||||
- (!) refactor: type list tools made an implementation detail of the library
|
||||
- (!) refactor: header files with the entire system definitions moved up in the directory tree
|
||||
- refactor: math functions constraints refactored
|
||||
- refactor: `si_quantities.h` added to improve compile-times
|
||||
- refactor: `validate_ascii_string` refactored to `is_basic_literal_character_set`
|
||||
- refactor: `underlying_type` split to `wrapped_type` and `value_type` and used in code
|
||||
- refactor: code refactored to comply with clang-tidy
|
||||
- refactor: remove dependency on `<ranges>` header and switch to use an iterator-based `copy` algorithm
|
||||
- refactor: `terminate` replaced with `abort` and a header file added
|
||||
- fix: `QuantityLike` conversions required `Q::rep` instead of using one provided by `quantity_like_traits`
|
||||
- fix: `QuantitySpec[Unit]` replaced with `make_reference` in `value_cast`
|
||||
- fix: `ice_point` is now defined with the integral offset from `absolute_zero`
|
||||
- fix: performance regression in `sudo_cast` fixed
|
||||
- fix: explicit object parameter support fixed
|
||||
- fix: missing `version` header file added to `hacks.h`
|
||||
- fix: `quantity_cast` to accept lvalue references (thanks [@burnpanck](https://github.com/burnpanck))
|
||||
- fix: `value_cast` with lvalue references to `quantity_point` (thanks [@burnpanck](https://github.com/burnpanck))
|
||||
- docs: project blog and first posts added
|
||||
- docs: project documentation layout refactored
|
||||
- docs: "Interoperability with Other Libraries" chapter added
|
||||
@ -56,16 +76,32 @@
|
||||
- docs: mkdocs social plugin enabled
|
||||
- docs: project logo and custom color scheme added
|
||||
- docs: minimum compiler requirements updated
|
||||
- docs: unit symbols admonition extended in the "Quick Start" chapter
|
||||
- docs: Cairo dependency described in the MkDocs section
|
||||
- docs: "hello units" example updated with dimensions output
|
||||
- docs: "Text Output" chapter updated with the recent formatting changes
|
||||
- docs: formatting grammar language changed to EBNF
|
||||
- docs: "Project structure" chapter expanded
|
||||
- (!) build: Conan and CMake options refactored
|
||||
- (!) build: `MP_UNITS_AS_SYSTEM_HEADERS` support removed
|
||||
- (!) build: `MP_UNITS_AS_SYSTEM_HEADERS` renamed to `MP_UNITS_BUILD_AS_SYSTEM_HEADERS`
|
||||
- (!) build: `MP_UNITS_BUILD_LA` and `MP_UNITS_IWYU` CMake options now have `_DEV_` in the name
|
||||
- build: gsl-lite updated to 0.41.0
|
||||
- build: catch2 updated to 3.5.1
|
||||
- build: fmt updated to 10.2.1
|
||||
- build: gitpod environment updated
|
||||
- build: `check_cxx_feature_supported` added
|
||||
- build: IWYU path handling fixed
|
||||
- build: IWYU enabled on GCC
|
||||
- build: `CMAKE_EXPORT_COMPILE_COMMANDS` flag enabled for the developer's build
|
||||
- build(conan): `generate()` now set `cache_variables`
|
||||
- build(conan): `can_run` check added before running tests
|
||||
- ci: Conan and CMake CI now use different cache names
|
||||
- ci: gcc-14 added
|
||||
|
||||
### 2.1.1 <small>May 16, 2024</small> { id="2.1.1" }
|
||||
|
||||
- fix: unit tests compilation on gcc-14 fixed
|
||||
- fix: explicit `this` parameter support fixed
|
||||
|
||||
### 2.1.0 <small>December 9, 2023</small> { id="2.1.0" }
|
||||
|
||||
|
12
CITATION.cff
12
CITATION.cff
@ -36,13 +36,13 @@ contact:
|
||||
given-names: Mateusz
|
||||
family-names: Pusz
|
||||
|
||||
repository-code: "https://github.com/mpusz/units"
|
||||
url: "https://mpusz.github.io/units"
|
||||
repository-code: "https://github.com/mpusz/mp-units"
|
||||
url: "https://mpusz.github.io/mp-units"
|
||||
repository-artifact: "https://conan.io/center/mp-units"
|
||||
|
||||
version: 0.7.0
|
||||
date-released: "2021-05-11"
|
||||
version: 2.1.1
|
||||
date-released: "2024-05-16"
|
||||
identifiers:
|
||||
- description: "The GitHub release URL of tag 0.7.0"
|
||||
- description: "The GitHub release URL of tag 2.1.1"
|
||||
type: url
|
||||
value: "https://github.com/mpusz/units/releases/tag/v0.7.0"
|
||||
value: "https://github.com/mpusz/mp-units/releases/tag/v2.1.1"
|
||||
|
@ -67,8 +67,10 @@ endif()
|
||||
# add project code
|
||||
add_subdirectory(src)
|
||||
|
||||
# add usage example
|
||||
add_subdirectory(example)
|
||||
if(NOT ${projectPrefix}API_FREESTANDING)
|
||||
# add usage example
|
||||
add_subdirectory(example)
|
||||
endif()
|
||||
|
||||
# add unit tests
|
||||
enable_testing()
|
||||
|
12
README.md
12
README.md
@ -1,11 +1,13 @@
|
||||
<img align="right" height=135px src="docs/assets/images/mp-units-color.svg">
|
||||
|
||||
[](./LICENSE.md)
|
||||
[](https://en.cppreference.com/w/cpp/compiler_support#cpp20)
|
||||
[](https://en.cppreference.com/w/cpp/compiler_support#cpp20)
|
||||
|
||||
[](https://github.com/mpusz/mp-units/actions?query=workflow%3A%22Conan%20CI%22+branch%3Amaster)
|
||||
[](https://github.com/mpusz/mp-units/actions?query=workflow%3A%22CMake+Test+Package+CI%22+branch%3Amaster)
|
||||
[](https://github.com/mpusz/mp-units/actions?query=workflow%3A%22Formatting%20CI%22+branch%3Amaster)
|
||||
[](https://github.com/mpusz/mp-units/actions/workflows/ci-conan.yml)
|
||||
[](https://github.com/mpusz/mp-units/actions/workflows/ci-test-package-cmake.yml)
|
||||
[](https://github.com/mpusz/mp-units/actions/workflows/ci-clang-tidy.yml)
|
||||
[](https://github.com/mpusz/mp-units/actions/workflows/ci-freestanding.yml)
|
||||
[](https://github.com/mpusz/mp-units/actions/workflows/ci-formatting.yml)
|
||||
[](https://github.com/mpusz/mp-units/actions?query=workflow%3ADocumentation+branch%3Amaster)
|
||||
|
||||
[](https://conan.io/center/mp-units)
|
||||
@ -130,4 +132,4 @@ int main()
|
||||
}
|
||||
```
|
||||
|
||||
_Try it on the [Compiler Explorer](https://godbolt.org/z/fsdovTcYh)._
|
||||
_Try it on the [Compiler Explorer](https://godbolt.org/z/nhqhT8Mzb)._
|
||||
|
37
conanfile.py
37
conanfile.py
@ -65,12 +65,16 @@ class MPUnitsConan(ConanFile):
|
||||
"std_format": ["auto", True, False],
|
||||
"string_view_ret": ["auto", True, False],
|
||||
"no_crtp": ["auto", True, False],
|
||||
"contracts": ["none", "gsl-lite", "ms-gsl"],
|
||||
"freestanding": [True, False],
|
||||
}
|
||||
default_options = {
|
||||
"cxx_modules": "auto",
|
||||
"std_format": "auto",
|
||||
"string_view_ret": "auto",
|
||||
"no_crtp": "auto",
|
||||
"contracts": "gsl-lite",
|
||||
"freestanding": "False",
|
||||
}
|
||||
tool_requires = "cmake/[>=3.29]"
|
||||
implements = "auto_header_only"
|
||||
@ -191,6 +195,10 @@ class MPUnitsConan(ConanFile):
|
||||
def _skip_la(self):
|
||||
return bool(self.conf.get("user.mp-units.build:skip_la", default=False))
|
||||
|
||||
@property
|
||||
def _run_clang_tidy(self):
|
||||
return bool(self.conf.get("user.mp-units.analyze:clang-tidy", default=False))
|
||||
|
||||
def set_version(self):
|
||||
content = load(self, os.path.join(self.recipe_folder, "src/CMakeLists.txt"))
|
||||
version = re.search(
|
||||
@ -199,13 +207,17 @@ class MPUnitsConan(ConanFile):
|
||||
self.version = version.strip()
|
||||
|
||||
def requirements(self):
|
||||
self.requires("gsl-lite/0.41.0")
|
||||
if self._use_fmtlib:
|
||||
if self.options.contracts == "gsl-lite":
|
||||
self.requires("gsl-lite/0.41.0")
|
||||
elif self.options.contracts == "ms-gsl":
|
||||
self.requires("ms-gsl/4.0.0")
|
||||
if self._use_fmtlib and not self.options.freestanding:
|
||||
self.requires("fmt/10.2.1")
|
||||
|
||||
def build_requirements(self):
|
||||
if self._build_all:
|
||||
self.test_requires("catch2/3.5.1")
|
||||
if not self.options.freestanding:
|
||||
self.test_requires("catch2/3.5.1")
|
||||
if not self._skip_la:
|
||||
self.test_requires("wg21-linear_algebra/0.7.3")
|
||||
|
||||
@ -214,16 +226,23 @@ class MPUnitsConan(ConanFile):
|
||||
for key, value in self._option_feature_map.items():
|
||||
if self.options.get_safe(key) == True:
|
||||
self._check_feature_supported(key, value)
|
||||
if self.options.freestanding and self.options.contracts != "none":
|
||||
raise ConanInvalidConfiguration(
|
||||
"'contracts' should be set to 'none' for a freestanding build"
|
||||
)
|
||||
|
||||
def layout(self):
|
||||
cmake_layout(self)
|
||||
|
||||
def generate(self):
|
||||
tc = CMakeToolchain(self)
|
||||
tc.absolute_paths = True # only needed for CMake CI
|
||||
if self._build_all:
|
||||
tc.cache_variables["CMAKE_EXPORT_COMPILE_COMMANDS"] = True
|
||||
tc.cache_variables["CMAKE_VERIFY_INTERFACE_HEADER_SETS"] = True
|
||||
tc.cache_variables["MP_UNITS_DEV_BUILD_LA"] = not self._skip_la
|
||||
if self._run_clang_tidy:
|
||||
tc.cache_variables["MP_UNITS_DEV_CLANG_TIDY"] = True
|
||||
if self._build_cxx_modules:
|
||||
tc.cache_variables["CMAKE_CXX_SCAN_FOR_MODULES"] = True
|
||||
tc.cache_variables["MP_UNITS_BUILD_CXX_MODULES"] = str(
|
||||
@ -236,6 +255,10 @@ class MPUnitsConan(ConanFile):
|
||||
self.options.string_view_ret
|
||||
).upper()
|
||||
tc.cache_variables["MP_UNITS_API_NO_CRTP"] = str(self.options.no_crtp).upper()
|
||||
tc.cache_variables["MP_UNITS_API_CONTRACTS"] = str(
|
||||
self.options.contracts
|
||||
).upper()
|
||||
tc.cache_variables["MP_UNITS_API_FREESTANDING"] = self.options.freestanding
|
||||
tc.generate()
|
||||
deps = CMakeDeps(self)
|
||||
deps.generate()
|
||||
@ -262,8 +285,12 @@ class MPUnitsConan(ConanFile):
|
||||
|
||||
def package_info(self):
|
||||
compiler = self.settings.compiler
|
||||
self.cpp_info.components["core"].requires = ["gsl-lite::gsl-lite"]
|
||||
if self._use_fmtlib:
|
||||
self.cpp_info.components["core"]
|
||||
if self.options.contracts == "gsl-lite":
|
||||
self.cpp_info.components["core"].requires = ["gsl-lite::gsl-lite"]
|
||||
elif self.options.contracts == "ms-gsl":
|
||||
self.cpp_info.components["core"].requires = ["ms-gsl::ms-gsl"]
|
||||
if self._use_fmtlib and not self.options.freestanding:
|
||||
self.cpp_info.components["core"].requires.append("fmt::fmt")
|
||||
if compiler == "msvc":
|
||||
self.cpp_info.components["core"].cxxflags = ["/utf-8"]
|
||||
|
@ -31,12 +31,12 @@ the C++ modules' support is still really limited.
|
||||
|
||||
To benefit from C++ modules, we need at least:
|
||||
|
||||
- CMake 3.28.1
|
||||
- CMake 3.29.3
|
||||
- Ninja 1.11
|
||||
- clang-17
|
||||
|
||||
In the upcoming months, hopefully, the situation will improve with the gcc-14 release and
|
||||
bug fixes in MSVC.
|
||||
In the upcoming months, hopefully, the situation will improve with the bug fixes in
|
||||
CMake, gcc-14, and MSVC.
|
||||
|
||||
!!! note
|
||||
|
||||
@ -64,6 +64,11 @@ flowchart TD
|
||||
The easiest way to use them is just to `import mp_units;` at the beginning of your translation unit
|
||||
(see the [Quick Start](../../getting_started/quick_start.md) chapter for some usage examples).
|
||||
|
||||
!!! note
|
||||
|
||||
C++20 modules support still have some issues when imported from the installed CMake target.
|
||||
See the following [GitLab issue for more details](https://gitlab.kitware.com/cmake/cmake/-/issues/25909#note_1525377).
|
||||
|
||||
In this release, we also highly limited the number of CMake targets (:boom: **breaking change** :boom:).
|
||||
Now, they correspond exactly to the C++ modules they provide. This means that many smaller partial
|
||||
targets were removed. We also merged text output targets with the core library's definition.
|
||||
@ -93,9 +98,9 @@ In version 2.2, the following headers have a new location or contents:
|
||||
Benefiting from this opportunity, we also cleaned up core and systems definitions
|
||||
(:boom: **breaking change** :boom:).
|
||||
|
||||
Regarding the library's core, we exposed only one header `framework.h` that exposes all of
|
||||
the library's framework so the user does not have to enumerate files like `unit.h`, `quantity.h`,
|
||||
and `quantity_point.h` anymore. Those headers are not gone, they were put to
|
||||
Regarding the library's core, we removed `core.h` and exposed only one header `framework.h` that
|
||||
provides all of the library's framework so the user does not have to enumerate files like `unit.h`,
|
||||
`quantity.h`, and `quantity_point.h` anymore. Those headers are not gone, they were put to
|
||||
the `mp-units/framework` subheader. So they are still there if you really need them.
|
||||
|
||||
Regarding the changes in systems definitions, we moved the wrapper header files with the entire
|
||||
@ -161,6 +166,21 @@ Additionally, some CMake options were renamed to better express the impact on ou
|
||||
- `MP_UNITS_DEV_*` - options primarily useful for the project developers or people who want to
|
||||
compile our unit tests and examples.
|
||||
|
||||
|
||||
## Configurable contracts checking
|
||||
|
||||
Before this release, the library always depended on [gsl-lite](https://github.com/gsl-lite/gsl-lite)
|
||||
to perform runtime contract and asserts checking. In this release we introduced new options
|
||||
to control if contract checking should be based on [gsl-lite](https://github.com/gsl-lite/gsl-lite),
|
||||
[ms-gsl](https://github.com/microsoft/GSL), or maybe completely disabled.
|
||||
|
||||
|
||||
## Freestanding support
|
||||
|
||||
From this release it is possible to configure the library in the
|
||||
[freestanding](https://en.cppreference.com/w/cpp/freestanding) mode. This limits the functionality
|
||||
and interface of the library to be compatible with the freestanding implementations.
|
||||
|
||||
!!! info
|
||||
|
||||
To learn more, please refer to the [Build options](../../getting_started/installation_and_usage.md#build-options)
|
||||
@ -191,7 +211,7 @@ origins. For example:
|
||||
```
|
||||
|
||||
As we can see above, the new design allows
|
||||
[direct-initialization](https://en.cppreference.com/w/cpp/language/direct_initialization) of a
|
||||
[direct-initializing](https://en.cppreference.com/w/cpp/language/direct_initialization)
|
||||
`quantity_point` class template from a `quantity`, but only if the former one is defined in terms
|
||||
of the implicit point origin. Otherwise, an explicit origin still always has to be provided during
|
||||
initialization.
|
||||
@ -199,7 +219,7 @@ initialization.
|
||||
Also, we introduced the possibility of specifying a default point origin in the unit definition.
|
||||
With that, we could provide proper temperature scales without forcing the user to always use
|
||||
the origins explicitly. Also, a new member function, `.quantity_from_zero(),` was introduced
|
||||
that always returns the quantity from the unit's specific point origin or from the absolute
|
||||
that always returns the quantity from the unit's specific point origin or from the implicit
|
||||
point origin otherwise.
|
||||
|
||||
=== "Now"
|
||||
@ -244,20 +264,30 @@ named with its corresponding unit and with the `si::zeroth_degree_Celsius`
|
||||
about potential ABI issues when different translation units are compiled with different ordinary
|
||||
literal encodings. Those issues were resolved with a change to units definitions
|
||||
(:boom: **breaking change** :boom:). It affects only units that specify both Unicode and ASCII
|
||||
symbols. The new design requires the Unicode symbol to be provided as a UTF-8 literal:
|
||||
symbols. The new design requires the Unicode symbol to be provided as a UTF-8 literal.
|
||||
|
||||
This also means that the `basic_symbol_text` has fixed character types for both symbols. This
|
||||
is why it was renamed to `symbol_text` (:boom: **breaking change** :boom:).
|
||||
|
||||
=== "Now"
|
||||
|
||||
```cpp
|
||||
inline constexpr struct ohm : named_unit<{u8"Ω", "ohm"}, volt / ampere> {} ohm;
|
||||
inline constexpr struct ohm : named_unit<symbol_text{u8"Ω", "ohm"}, volt / ampere> {} ohm;
|
||||
```
|
||||
|
||||
=== "Before"
|
||||
|
||||
```cpp
|
||||
inline constexpr struct ohm : named_unit<{"Ω", "ohm"}, volt / ampere> {} ohm;
|
||||
inline constexpr struct ohm : named_unit<basic_symbol_text{"Ω", "ohm"}, volt / ampere> {} ohm;
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
On C++20-compliant compilers it should be enough to type the following in the unit's definition:
|
||||
|
||||
```cpp
|
||||
inline constexpr struct ohm : named_unit<{u8"Ω", "ohm"}, volt / ampere> {} ohm;
|
||||
```
|
||||
|
||||
## Improved text output
|
||||
|
||||
@ -333,7 +363,7 @@ Example 1 (clang):
|
||||
61 | concept QuantityOf = Quantity<Q> && QuantitySpecOf<std::remove_const_t<decltype(Q::quantity_spec)>, QS>;
|
||||
| ^
|
||||
note: because 'implicitly_convertible(kind_of_<derived_quantity_spec<isq::time, per<isq::length> > >{}, struct speed{{{}}})' evaluated to false
|
||||
147 | QuantitySpec<T> && QuantitySpec<std::remove_const_t<decltype(QS)>> && implicitly_convertible(T{}, QS) &&
|
||||
147 | QuantitySpec<T> && QuantitySpec<decltype(QS)> && implicitly_convertible(T{}, QS) &&
|
||||
| ^
|
||||
1 error generated.
|
||||
Compiler returned: 1
|
||||
@ -356,7 +386,7 @@ Example 1 (clang):
|
||||
61 | concept QuantityOf = Quantity<Q> && QuantitySpecOf<std::remove_const_t<decltype(Q::quantity_spec)>, QS>;
|
||||
| ^
|
||||
note: because 'implicitly_convertible(kind_of_<derived_quantity_spec<isq::time, per<isq::length> >{{}, {{}}}>{}, struct speed{{{}}})' evaluated to false
|
||||
147 | QuantitySpec<T> && QuantitySpec<std::remove_const_t<decltype(QS)>> && implicitly_convertible(T{}, QS) &&
|
||||
147 | QuantitySpec<T> && QuantitySpec<decltype(QS)> && implicitly_convertible(T{}, QS) &&
|
||||
| ^
|
||||
1 error generated.
|
||||
Compiler returned: 1
|
||||
|
@ -13,13 +13,13 @@
|
||||
The table below provides the minimum compiler version required to compile the code using a specific
|
||||
C++ feature:
|
||||
|
||||
| C++ Feature | C++ version | gcc | clang | apple-clang | MSVC |
|
||||
|-----------------------------------------------------------|:-----------:|:---:|:-----:|:-----------:|:----:|
|
||||
| **Minimum support** | 20 | 12 | 16 | 15 | None |
|
||||
| **`std::format`** | 20 | 13 | 17 | None | None |
|
||||
| **C++ modules** | 20 | 14 | 17 | None | None |
|
||||
| **Static `constexpr` variables in `constexpr` functions** | 23 | 13 | 17 | None | None |
|
||||
| **Explicit `this` parameter** | 23 | 14 | 18 | None | None |
|
||||
| C++ Feature | C++ version | gcc | clang | apple-clang | MSVC |
|
||||
|-----------------------------------------------------------|:-----------:|:----:|:-----:|:-----------:|:----:|
|
||||
| **Minimum support** | 20 | 12 | 16 | 15 | None |
|
||||
| **`std::format`** | 20 | 13 | 17 | None | None |
|
||||
| **C++ modules** | 20 | None | 17 | None | None |
|
||||
| **Static `constexpr` variables in `constexpr` functions** | 23 | 13 | 17 | None | None |
|
||||
| **Explicit `this` parameter** | 23 | 14 | 18 | None | None |
|
||||
|
||||
!!! important
|
||||
|
||||
@ -29,7 +29,7 @@ C++ feature:
|
||||
|
||||
## `std::format`
|
||||
|
||||
- Provides [powerful text formatting capabilities](../users_guide/framework_basics/text_output.md#stdformat)
|
||||
- Provides [powerful text formatting capabilities](../users_guide/framework_basics/text_output.md#text-formatting)
|
||||
for C++.
|
||||
- An alternative [fmtlib](https://github.com/fmtlib/fmt) library can be used instead if
|
||||
- the C++ language feature is not supported,
|
||||
|
@ -176,7 +176,7 @@ we have to obey the rules and be consistent with ISO specifications.
|
||||
!!! note
|
||||
|
||||
We do understand engineering reality and the constraints of some environments. This is why the library
|
||||
has the option of [ASCII-only Quantity Symbols](../users_guide/framework_basics/text_output.md#unit-symbol-formatting).
|
||||
has the option of [ASCII-only Quantity Symbols](../users_guide/framework_basics/text_output.md#unit_symbol_formatting).
|
||||
|
||||
|
||||
## Why don't we have CMake options to disable the building of tests and examples?
|
||||
|
@ -18,8 +18,8 @@ projects:
|
||||
- in case this library becomes part of the C++ standard, it will have no external dependencies
|
||||
but until then, it depends on the following:
|
||||
|
||||
- [gsl-lite](https://github.com/gsl-lite/gsl-lite) to verify runtime contracts with
|
||||
the `gsl_Expects` macro,
|
||||
- [gsl-lite](https://github.com/gsl-lite/gsl-lite) or [ms-gsl](https://github.com/microsoft/GSL)
|
||||
to verify runtime contracts (if contract checking is enabled),
|
||||
- [{fmt}](https://github.com/fmtlib/fmt) to provide text formatting of quantities
|
||||
(if `std::format` is not supported yet on a specific compiler).
|
||||
|
||||
@ -56,7 +56,7 @@ projects:
|
||||
handle the dependencies.
|
||||
|
||||
To learn more about the rationale, please check our
|
||||
[FAQ](faq.md#why-dont-we-have-cmake-options-to-disable-building-of-tests-and-examples).
|
||||
[FAQ](faq.md#why-dont-we-have-cmake-options-to-disable-the-building-of-tests-and-examples).
|
||||
|
||||
### Modules
|
||||
|
||||
@ -229,7 +229,7 @@ tools.build:compiler_executables={"c": "gcc-12", "cpp": "g++-12"}
|
||||
|
||||
### Conan options
|
||||
|
||||
[cxx_modules](#cxx_modules){ #cxx_modules }
|
||||
[`cxx_modules`](#cxx_modules){ #cxx_modules }
|
||||
|
||||
: [:octicons-tag-24: 2.2.0][conan C++ modules support] · :octicons-milestone-24: `auto`/`True`/`False` (Default: `auto`)
|
||||
|
||||
@ -237,7 +237,7 @@ tools.build:compiler_executables={"c": "gcc-12", "cpp": "g++-12"}
|
||||
|
||||
[conan C++ modules support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
[std_format](#std_format){ #std_format }
|
||||
[`std_format`](#std_format){ #std_format }
|
||||
|
||||
: [:octicons-tag-24: 2.2.0][conan std::format support] · :octicons-milestone-24: `auto`/`True`/`False` (Default: `auto`)
|
||||
|
||||
@ -247,7 +247,7 @@ tools.build:compiler_executables={"c": "gcc-12", "cpp": "g++-12"}
|
||||
|
||||
[conan std::format support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
[string_view_ret](#string_view_ret){ #string_view_ret }
|
||||
[`string_view_ret`](#string_view_ret){ #string_view_ret }
|
||||
|
||||
: [:octicons-tag-24: 2.2.0][conan returning string_view] · :octicons-milestone-24: `auto`/`True`/`False` (Default: `auto`)
|
||||
|
||||
@ -259,7 +259,7 @@ tools.build:compiler_executables={"c": "gcc-12", "cpp": "g++-12"}
|
||||
|
||||
[conan returning string_view]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
[no_crtp](#no_crtp){ #no_crtp }
|
||||
[`no_crtp`](#no_crtp){ #no_crtp }
|
||||
|
||||
: [:octicons-tag-24: 2.2.0][conan no crtp support] · :octicons-milestone-24: `auto`/`True`/`False` (Default: `auto`)
|
||||
|
||||
@ -268,6 +268,24 @@ tools.build:compiler_executables={"c": "gcc-12", "cpp": "g++-12"}
|
||||
|
||||
[conan no crtp support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
[`contracts`](#contracts){ #contracts }
|
||||
|
||||
: [:octicons-tag-24: 2.2.0][conan contracts] · :octicons-milestone-24: `none`/`gsl-lite`/`ms-gsl` (Default: `gsl-lite`)
|
||||
|
||||
Enables checking of preconditions and additional asserts in the code.
|
||||
|
||||
[conan contracts]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
[`freestanding`](#freestanding){ #freestanding }
|
||||
|
||||
: [:octicons-tag-24: 2.2.0][conan freestanding] · :octicons-milestone-24: `True`/`False` (Default: `False`)
|
||||
|
||||
Configures the library in the [freestanding](https://en.cppreference.com/w/cpp/freestanding)
|
||||
mode. When enabled, the library's source code should build with the compiler's
|
||||
[`-ffreestanding`](https://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html) compilation option
|
||||
without any issues.
|
||||
|
||||
[conan freestanding]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
### Conan configuration properties
|
||||
|
||||
@ -276,7 +294,7 @@ tools.build:compiler_executables={"c": "gcc-12", "cpp": "g++-12"}
|
||||
: [:octicons-tag-24: 2.2.0][conan 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).
|
||||
[Repository directory tree and dependencies](#repository-directory-tree-and-dependencies).
|
||||
It also runs unit tests during Conan build (unless
|
||||
[`tools.build:skip_test`](https://docs.conan.io/2/reference/commands/config.html?highlight=tools.build:skip_test#conan-config-list)
|
||||
configuration property is set to `True`).
|
||||
@ -296,6 +314,14 @@ tools.build:compiler_executables={"c": "gcc-12", "cpp": "g++-12"}
|
||||
[conan skip la support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
|
||||
[`user.mp-units.analyze:clang-tidy`](#user.mp-units.analyze-clang-tidy){ #user.mp-units.analyze-clang-tidy }
|
||||
|
||||
: [:octicons-tag-24: 2.2.0][conan clang-tidy support] · :octicons-milestone-24: `True`/`False` (Default: `False`)
|
||||
|
||||
Enables clang-tidy analysis.
|
||||
|
||||
[conan clang-tidy support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
### CMake options
|
||||
|
||||
[`MP_UNITS_BUILD_AS_SYSTEM_HEADERS`](#MP_UNITS_BUILD_AS_SYSTEM_HEADERS){ #MP_UNITS_BUILD_AS_SYSTEM_HEADERS }
|
||||
@ -345,24 +371,50 @@ tools.build:compiler_executables={"c": "gcc-12", "cpp": "g++-12"}
|
||||
|
||||
[cmake no crtp support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
[`MP_UNITS_API_CONTRACTS`](#MP_UNITS_API_CONTRACTS){ #MP_UNITS_API_CONTRACTS }
|
||||
|
||||
: [:octicons-tag-24: 2.2.0][cmake contracts] · :octicons-milestone-24: `NONE`/`GSL-LITE`/`MS-GSL` (Default: `GSL-LITE`)
|
||||
|
||||
Enables checking of preconditions and additional asserts in the code.
|
||||
|
||||
[cmake contracts]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
[`MP_UNITS_API_FREESTANDING`](#MP_UNITS_API_FREESTANDING){ #MP_UNITS_API_FREESTANDING }
|
||||
|
||||
: [:octicons-tag-24: 2.2.0][cmake freestanding] · :octicons-milestone-24: `ON`/`OFF` (Default: `OFF`)
|
||||
|
||||
Configures the library in the [freestanding](https://en.cppreference.com/w/cpp/freestanding)
|
||||
mode. When enabled, the library's source code should build with the compiler's
|
||||
[`-ffreestanding`](https://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html) compilation option
|
||||
without any issues.
|
||||
|
||||
[cmake freestanding]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
#### Options for mp-units project developers
|
||||
|
||||
[`MP_UNITS_DEV_BUILD_LA`](#MP_UNITS_DEV_BUILD_LA){ #MP_UNITS_DEV_BUILD_LA }
|
||||
|
||||
: [:octicons-tag-24: 2.0.0][build la support] · :octicons-milestone-24: `ON`/`OFF` (Default: `ON`)
|
||||
: [:octicons-tag-24: 2.2.0][cmake build la support] · :octicons-milestone-24: `ON`/`OFF` (Default: `ON`)
|
||||
|
||||
Enables building code depending on the linear algebra library.
|
||||
|
||||
[build la support]: https://github.com/mpusz/mp-units/releases/tag/v2.0.0
|
||||
|
||||
[cmake build la support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
[`MP_UNITS_DEV_IWYU`](#MP_UNITS_DEV_IWYU){ #MP_UNITS_DEV_IWYU }
|
||||
|
||||
: [:octicons-tag-24: 2.0.0][iwyu support] · :octicons-milestone-24: `ON`/`OFF` (Default: `OFF`)
|
||||
: [:octicons-tag-24: 2.2.0][cmake iwyu support] · :octicons-milestone-24: `ON`/`OFF` (Default: `OFF`)
|
||||
|
||||
Enables `include-what-you-use` when compiling with a clang compiler.
|
||||
Enables include-what-you-use analysis.
|
||||
|
||||
[iwyu support]: https://github.com/mpusz/mp-units/releases/tag/v2.0.0
|
||||
[cmake iwyu support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
[`MP_UNITS_DEV_CLANG_TIDY`](#MP_UNITS_DEV_CLANG_TIDY){ #MP_UNITS_DEV_CLANG_TIDY }
|
||||
|
||||
: [:octicons-tag-24: 2.2.0][cmake clang-tidy support] · :octicons-milestone-24: `ON`/`OFF` (Default: `OFF`)
|
||||
|
||||
Enables clang-tidy analysis.
|
||||
|
||||
[cmake clang-tidy support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
|
||||
|
||||
|
||||
## CMake with presets support
|
||||
|
@ -80,6 +80,6 @@ To achieve this goal, several techniques are applied:
|
||||
[Highly adjustable text-output formatting]: ../users_guide/framework_basics/text_output.md
|
||||
|
||||
[Each entity can be defined with a single line of code]: ../users_guide/framework_basics/interface_introduction.md#new-style-of-definitions
|
||||
[User can easily extend the systems with custom dimensions, quantities, and units]: ../users_guide/use_cases/extending_the_library.md#new-style-of-definitions
|
||||
[User can easily extend the systems with custom dimensions, quantities, and units]: ../users_guide/use_cases/extending_the_library.md
|
||||
|
||||
[freestanding]: https://en.cppreference.com/w/cpp/freestanding
|
||||
|
@ -150,7 +150,7 @@ performed without sacrificing accuracy. Please see the below example for a quick
|
||||
}
|
||||
```
|
||||
|
||||
!!! example "[Try it on Compiler Explorer](https://godbolt.org/z/fsdovTcYh)"
|
||||
!!! example "[Try it on Compiler Explorer](https://godbolt.org/z/nhqhT8Mzb)"
|
||||
|
||||
!!! note
|
||||
|
||||
|
@ -95,7 +95,7 @@ and when `T` is implicitly convertible to `V`.
|
||||
and is satisfied by:
|
||||
|
||||
- All units derived from a `named_unit` class template instantiated with a unique symbol identifier
|
||||
and a [`QuantitySpec`](#quantityspec) of a [quantity kind](../../appendix/glossary.md#kind).
|
||||
and a [`QuantitySpec`](#QuantitySpec) of a [quantity kind](../../appendix/glossary.md#kind).
|
||||
- All units being a result of [unit equations](../../appendix/glossary.md#unit-equation) on other
|
||||
associated units.
|
||||
|
||||
|
@ -231,8 +231,8 @@ For example:
|
||||
A unit can be defined by the user in one of the following ways:
|
||||
|
||||
```cpp
|
||||
template<PrefixableUnit auto U> struct kilo_ : prefixed_unit<"k", mag_power<10, 3>, U> {};
|
||||
template<PrefixableUnit auto U> inline constexpr kilo_<U> kilo;
|
||||
template<PrefixableUnit U> struct kilo_ : prefixed_unit<"k", mag_power<10, 3>, U{}> {};
|
||||
template<PrefixableUnit auto U> inline constexpr kilo_<decltype(U)> kilo;
|
||||
|
||||
inline constexpr struct second : named_unit<"s", kind_of<isq::time>> {} second;
|
||||
inline constexpr struct minute : named_unit<"min", mag<60> * second> {} minute;
|
||||
|
@ -137,8 +137,8 @@ unit magnitude in a more flexible way.
|
||||
Each prefix is implemented similarly to the following:
|
||||
|
||||
```cpp
|
||||
template<PrefixableUnit auto U> struct quecto_ : prefixed_unit<"q", mag_power<10, -30>, U> {};
|
||||
template<PrefixableUnit auto U> inline constexpr quecto_<U> quecto;
|
||||
template<PrefixableUnit U> struct quecto_ : prefixed_unit<"q", mag_power<10, -30>, U{}> {};
|
||||
template<PrefixableUnit auto U> inline constexpr quecto_<decltype(U)> quecto;
|
||||
```
|
||||
|
||||
and then a [PrefixableUnit](concepts.md#PrefixableUnit) can be prefixed in the following
|
||||
@ -153,8 +153,8 @@ efficiently represent any rational magnitude. For example, IEC 80000 prefixes us
|
||||
IT industry can be implemented as:
|
||||
|
||||
```cpp
|
||||
template<PrefixableUnit auto U> struct yobi_ : prefixed_unit<"Yi", mag_power<2, 80>, U> {};
|
||||
template<PrefixableUnit auto U> inline constexpr yobi_<U> yobi;
|
||||
template<PrefixableUnit U> struct yobi_ : prefixed_unit<"Yi", mag_power<2, 80>, U{}> {};
|
||||
template<PrefixableUnit auto U> inline constexpr yobi_<decltype(U)> yobi;
|
||||
```
|
||||
|
||||
## Scaled units
|
||||
|
@ -62,14 +62,14 @@ and units of derived quantities.
|
||||
=== "Prefixes"
|
||||
|
||||
```cpp
|
||||
template<PrefixableUnit auto U> struct micro_ : prefixed_unit<{u8"µ", "u"}, mag_power<10, -6>, U> {};
|
||||
template<PrefixableUnit auto 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 auto 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 auto 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 auto U> struct mega_ : prefixed_unit<"M", mag_power<10, 6>, U> {};
|
||||
template<PrefixableUnit U> struct micro_ : prefixed_unit<{u8"µ", "u"}, mag_power<10, -6>, U{}> {};
|
||||
template<PrefixableUnit U> struct milli_ : prefixed_unit<"m", mag_power<10, -3>, U{}> {};
|
||||
template<PrefixableUnit U> struct centi_ : prefixed_unit<"c", mag_power<10, -2>, U{}> {};
|
||||
template<PrefixableUnit U> struct deci_ : prefixed_unit<"d", mag_power<10, -1>, U{}> {};
|
||||
template<PrefixableUnit U> struct deca_ : prefixed_unit<"da", mag_power<10, 1>, U{}> {};
|
||||
template<PrefixableUnit U> struct hecto_ : prefixed_unit<"h", mag_power<10, 2>, U{}> {};
|
||||
template<PrefixableUnit U> struct kilo_ : prefixed_unit<"k", mag_power<10, 3>, U{}> {};
|
||||
template<PrefixableUnit U> struct mega_ : prefixed_unit<"M", mag_power<10, 6>, U{}> {};
|
||||
```
|
||||
|
||||
=== "Constants"
|
||||
@ -241,7 +241,7 @@ static_assert(unit_symbol<{.solidus = unit_symbol_solidus::never,
|
||||
|
||||
`std::string_view` is returned only when C++23 is available. Otherwise, an instance of a
|
||||
`basic_fixed_string` is being returned. See more in the
|
||||
[C++ compiler support](../../getting_started/installation_and_usage.md#static-constexpr-variables-in-constexpr-functions)
|
||||
[C++ compiler support](../../getting_started/cpp_compiler_support.md#static-constexpr-variables-in-constexpr-functions)
|
||||
chapter.
|
||||
|
||||
#### `unit_symbol_to()`
|
||||
|
@ -219,7 +219,7 @@ the origin and the _displacement vector_ measured from it to the point we create
|
||||
[Why can't I create a quantity by passing a number to a constructor?](../../getting_started/faq.md#why-cant-i-create-a-quantity-by-passing-a-number-to-a-constructor)
|
||||
chapter.
|
||||
|
||||
Similarly to [creation of a quantity](../../getting_started/quick_start.md#creating-a-quantity),
|
||||
Similarly to [creation of a quantity](../../getting_started/quick_start.md#quantities),
|
||||
if someone does not like the operator-based syntax to create a `quantity_point`, the same results
|
||||
can be achieved with a two-parameter constructor:
|
||||
|
||||
@ -403,7 +403,7 @@ inline constexpr struct zeroth_degree_Celsius : decltype(ice_point) {} zeroth_de
|
||||
namespace usc {
|
||||
|
||||
inline constexpr struct zeroth_degree_Fahrenheit :
|
||||
relative_point_origin<si::zeroth_degree_Celsius - 32 * (mag_ratio<5, 9> * si::degree_Celsius)> {} zeroth_degree_Fahrenheit;
|
||||
relative_point_origin<quantity_point{-32 * (mag_ratio<5, 9> * si::degree_Celsius)}> {} zeroth_degree_Fahrenheit;
|
||||
|
||||
}
|
||||
```
|
||||
|
@ -23,21 +23,37 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
# find dependencies
|
||||
if(NOT TARGET gsl::gsl-lite)
|
||||
find_package(gsl-lite REQUIRED)
|
||||
endif()
|
||||
|
||||
if(${projectPrefix}BUILD_CXX_MODULES)
|
||||
add_library(example_utils INTERFACE)
|
||||
target_compile_features(example_utils INTERFACE cxx_std_20)
|
||||
target_compile_definitions(example_utils INTERFACE ${projectPrefix}MODULES)
|
||||
target_include_directories(example_utils INTERFACE include)
|
||||
target_link_libraries(example_utils INTERFACE gsl::gsl-lite)
|
||||
endif()
|
||||
|
||||
add_library(example_utils-headers INTERFACE)
|
||||
target_include_directories(example_utils-headers INTERFACE include)
|
||||
target_link_libraries(example_utils-headers INTERFACE gsl::gsl-lite)
|
||||
|
||||
if(${projectPrefix}API_CONTRACTS STREQUAL "NONE")
|
||||
target_compile_definitions(mp-units-core INTERFACE ${projectPrefix}API_CONTRACTS=0)
|
||||
elseif(${projectPrefix}API_CONTRACTS STREQUAL "GSL-LITE")
|
||||
if(NOT TARGET gsl::gsl-lite)
|
||||
find_package(gsl-lite REQUIRED)
|
||||
endif()
|
||||
if(${projectPrefix}BUILD_CXX_MODULES)
|
||||
target_link_libraries(example_utils INTERFACE gsl::gsl-lite)
|
||||
endif()
|
||||
target_link_libraries(example_utils-headers INTERFACE gsl::gsl-lite)
|
||||
target_compile_definitions(mp-units-core INTERFACE ${projectPrefix}API_CONTRACTS=2)
|
||||
elseif(${projectPrefix}API_CONTRACTS STREQUAL "MS-GSL")
|
||||
if(NOT TARGET Microsoft.GSL::GSL)
|
||||
find_package(Microsoft.GSL REQUIRED)
|
||||
endif()
|
||||
if(${projectPrefix}BUILD_CXX_MODULES)
|
||||
target_link_libraries(example_utils INTERFACE Microsoft.GSL::GSL)
|
||||
endif()
|
||||
target_link_libraries(example_utils-headers INTERFACE Microsoft.GSL::GSL)
|
||||
target_compile_definitions(mp-units-core INTERFACE ${projectPrefix}API_CONTRACTS=3)
|
||||
endif()
|
||||
|
||||
#
|
||||
# add_example(target <depependencies>...)
|
||||
@ -72,4 +88,4 @@ add_example(total_energy)
|
||||
add_example(unmanned_aerial_vehicle example_utils)
|
||||
|
||||
add_subdirectory(glide_computer_lib)
|
||||
# add_subdirectory(kalman_filter)
|
||||
add_subdirectory(kalman_filter)
|
||||
|
@ -90,8 +90,6 @@ void print(const R& gliders)
|
||||
for (const auto& p : g.polar) {
|
||||
const auto ratio = glide_ratio(g.polar[0]).force_in(one);
|
||||
std::cout << MP_UNITS_STD_FMT::format(" * {::N[.4]} @ {::N[.1]} -> {::N[.1]} ({::N[.1]})\n", p.climb, p.v, ratio,
|
||||
// TODO is it possible to make ADL work below (we need another set of trig
|
||||
// functions for strong angle in a different namespace)
|
||||
si::asin(1 / ratio).force_in(si::degree));
|
||||
}
|
||||
std::cout << "\n";
|
||||
@ -168,8 +166,6 @@ void example()
|
||||
const auto weather_conditions = get_weather_conditions();
|
||||
const task t = {waypoints[0], waypoints[1], waypoints[0]};
|
||||
const aircraft_tow tow = {400 * m, 1.6 * m / s};
|
||||
// TODO use C++20 date library when available
|
||||
// set `start_time` to 11:00 am today
|
||||
const timestamp start_time(std::chrono::system_clock::now());
|
||||
|
||||
print(sfty);
|
||||
|
@ -22,7 +22,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gsl/gsl-lite.hpp>
|
||||
#include <mp-units/bits/hacks.h>
|
||||
#include <mp-units/compat_macros.h>
|
||||
#include <compare> // IWYU pragma: export
|
||||
@ -50,13 +49,13 @@ public:
|
||||
requires std::copyable<T>
|
||||
: value_(value)
|
||||
{
|
||||
gsl_Expects(validate(value_));
|
||||
MP_UNITS_EXPECTS(validate(value_));
|
||||
}
|
||||
|
||||
constexpr explicit validated_type(T&& value) noexcept(std::is_nothrow_move_constructible_v<T>) :
|
||||
value_(std::move(value))
|
||||
{
|
||||
gsl_Expects(validate(value_));
|
||||
MP_UNITS_EXPECTS(validate(value_));
|
||||
}
|
||||
|
||||
constexpr validated_type(const T& value, validated_tag) noexcept(std::is_nothrow_copy_constructible_v<T>)
|
||||
|
@ -23,21 +23,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <mp-units/compat_macros.h>
|
||||
#include <algorithm>
|
||||
#include <locale>
|
||||
#include <tuple>
|
||||
#ifdef MP_UNITS_MODULES
|
||||
import mp_units;
|
||||
#else
|
||||
#include <mp-units/ext/algorithm.h>
|
||||
#include <mp-units/format.h>
|
||||
#include <mp-units/framework/quantity.h>
|
||||
#include <mp-units/framework/quantity_point.h>
|
||||
#include <mp-units/math.h>
|
||||
#include <mp-units/quantity.h>
|
||||
#include <mp-units/quantity_point.h>
|
||||
#include <mp-units/systems/isq/space_and_time.h>
|
||||
#include <mp-units/systems/isq/base_quantities.h>
|
||||
#endif
|
||||
|
||||
namespace kalman {
|
||||
|
||||
template<typename T>
|
||||
concept QuantityOrQuantityPoint = mp_units::Quantity<T> || mp_units::QuantityPoint<T>;
|
||||
namespace detail {
|
||||
|
||||
template<mp_units::Dimension auto... Ds>
|
||||
inline constexpr bool are_time_derivatives = false;
|
||||
@ -49,192 +51,262 @@ template<mp_units::Dimension auto D1, mp_units::Dimension auto D2, mp_units::Dim
|
||||
inline constexpr bool are_time_derivatives<D1, D2, Ds...> =
|
||||
(D1 / D2 == mp_units::isq::dim_time) && are_time_derivatives<D2, Ds...>;
|
||||
|
||||
// state
|
||||
template<QuantityOrQuantityPoint... QQPs>
|
||||
requires(sizeof...(QQPs) > 0) && (sizeof...(QQPs) <= 3) && are_time_derivatives<QQPs::dimension...>
|
||||
struct state {
|
||||
std::tuple<QQPs...> variables_;
|
||||
constexpr state(QQPs... qqps) : variables_(std::move(qqps)...) {}
|
||||
} // namespace detail
|
||||
|
||||
// system state
|
||||
template<mp_units::QuantityPoint... QPs>
|
||||
requires(sizeof...(QPs) > 0) && (sizeof...(QPs) <= 3) && detail::are_time_derivatives<QPs::dimension...>
|
||||
class system_state {
|
||||
std::tuple<QPs...> variables_;
|
||||
public:
|
||||
constexpr explicit system_state(QPs... qps) : variables_(std::move(qps)...) {}
|
||||
|
||||
template<std::size_t Idx>
|
||||
[[nodiscard]] friend constexpr auto& get(system_state<QPs...>& s)
|
||||
{
|
||||
return get<Idx>(s.variables_);
|
||||
}
|
||||
|
||||
template<std::size_t Idx>
|
||||
[[nodiscard]] friend constexpr const auto& get(const system_state<QPs...>& s)
|
||||
{
|
||||
return get<Idx>(s.variables_);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
concept State = mp_units::is_specialization_of<T, state>;
|
||||
concept SystemState = mp_units::is_specialization_of<T, system_state>;
|
||||
|
||||
template<std::size_t Idx, typename... Qs>
|
||||
constexpr auto& get(state<Qs...>& s)
|
||||
{
|
||||
return get<Idx>(s.variables_);
|
||||
}
|
||||
|
||||
template<std::size_t Idx, typename... Qs>
|
||||
constexpr const auto& get(const state<Qs...>& s)
|
||||
{
|
||||
return get<Idx>(s.variables_);
|
||||
}
|
||||
|
||||
// estimation
|
||||
template<QuantityOrQuantityPoint QQP, QuantityOrQuantityPoint... QQPs>
|
||||
struct estimation {
|
||||
private:
|
||||
static constexpr auto uncertainty_ref = QQP::reference * QQP::reference;
|
||||
using uncertainty_type = mp_units::quantity<uncertainty_ref, typename QQP::rep>;
|
||||
// system state estimation
|
||||
template<mp_units::QuantityPoint QP, mp_units::QuantityPoint... Rest>
|
||||
requires requires { typename system_state<QP, Rest...>; }
|
||||
class system_state_estimate {
|
||||
public:
|
||||
kalman::state<QQP, QQPs...> state; // TODO extend kalman functions to work with this variadic parameter list
|
||||
uncertainty_type uncertainty;
|
||||
using state_type = system_state<QP, Rest...>;
|
||||
using standard_deviation_type = QP::quantity_type;
|
||||
using variance_type =
|
||||
mp_units::quantity<pow<2>(standard_deviation_type::reference), typename standard_deviation_type::rep>;
|
||||
private:
|
||||
state_type state_;
|
||||
variance_type variance_;
|
||||
public:
|
||||
constexpr system_state_estimate(state_type state, standard_deviation_type standard_deviation) :
|
||||
state_(state), variance_(pow<2>(standard_deviation))
|
||||
{
|
||||
}
|
||||
constexpr system_state_estimate(state_type state, variance_type variance) : state_(state), variance_(variance) {}
|
||||
[[nodiscard]] constexpr const state_type& state() const { return state_; }
|
||||
[[nodiscard]] constexpr const variance_type& variance() const { return variance_; }
|
||||
[[nodiscard]] constexpr standard_deviation_type standard_deviation() const { return sqrt(variance_); }
|
||||
};
|
||||
|
||||
template<QuantityOrQuantityPoint QQP, mp_units::Quantity U>
|
||||
estimation(state<QQP>, U) -> estimation<QQP>;
|
||||
|
||||
// kalman gain
|
||||
template<mp_units::Quantity Q>
|
||||
constexpr mp_units::quantity<mp_units::dimensionless[mp_units::one]> kalman_gain(Q estimate_uncertainty,
|
||||
Q measurement_uncertainty)
|
||||
template<mp_units::Quantity Q1, mp_units::Quantity Q2>
|
||||
requires requires { mp_units::common_reference(Q1::reference, Q2::reference); }
|
||||
[[nodiscard]] constexpr mp_units::quantity<mp_units::dimensionless[mp_units::one]> kalman_gain(
|
||||
Q1 variance_in_estimate, Q2 variance_in_measurement)
|
||||
{
|
||||
return estimate_uncertainty / (estimate_uncertainty + measurement_uncertainty);
|
||||
return variance_in_estimate / (variance_in_estimate + variance_in_measurement);
|
||||
}
|
||||
|
||||
// state update
|
||||
template<typename Q, QuantityOrQuantityPoint QM, mp_units::QuantityOf<mp_units::dimensionless> K>
|
||||
requires(implicitly_convertible(QM::quantity_spec, Q::quantity_spec))
|
||||
constexpr state<Q> state_update(const state<Q>& predicted, QM measured, K gain)
|
||||
template<typename QP, mp_units::QuantityPoint QM, mp_units::QuantityOf<mp_units::dimensionless> K>
|
||||
requires(implicitly_convertible(QM::quantity_spec, QP::quantity_spec))
|
||||
[[nodiscard]] constexpr system_state<QP> state_update(const system_state<QP>& predicted, QM measured, K gain)
|
||||
{
|
||||
return {get<0>(predicted) + gain * (measured - get<0>(predicted))};
|
||||
return system_state<QP>{get<0>(predicted) + gain * (measured - get<0>(predicted))};
|
||||
}
|
||||
|
||||
template<typename Q1, typename Q2, QuantityOrQuantityPoint QM, mp_units::QuantityOf<mp_units::dimensionless> K,
|
||||
template<typename QP1, typename QP2, mp_units::QuantityPoint QM, mp_units::QuantityOf<mp_units::dimensionless> K,
|
||||
mp_units::QuantityOf<mp_units::isq::time> T>
|
||||
requires(implicitly_convertible(QM::quantity_spec, Q1::quantity_spec))
|
||||
constexpr state<Q1, Q2> state_update(const state<Q1, Q2>& predicted, QM measured, std::array<K, 2> gain, T interval)
|
||||
requires(implicitly_convertible(QM::quantity_spec, QP1::quantity_spec))
|
||||
[[nodiscard]] constexpr system_state<QP1, QP2> state_update(const system_state<QP1, QP2>& predicted, QM measured,
|
||||
std::array<K, 2> gain, T interval)
|
||||
{
|
||||
const auto q1 = get<0>(predicted) + get<0>(gain) * (measured - get<0>(predicted));
|
||||
const auto q2 = get<1>(predicted) + get<1>(gain) * (measured - get<0>(predicted)) / interval;
|
||||
return {q1, q2};
|
||||
const auto qp1 = fma(get<0>(gain), measured - get<0>(predicted), get<0>(predicted));
|
||||
const auto qp2 = fma(get<1>(gain), (measured - get<0>(predicted)) / interval, get<1>(predicted));
|
||||
return system_state<QP1, QP2>{qp1, qp2};
|
||||
}
|
||||
|
||||
template<typename Q1, typename Q2, typename Q3, QuantityOrQuantityPoint QM,
|
||||
template<typename QP1, typename QP2, typename QP3, mp_units::QuantityPoint QM,
|
||||
mp_units::QuantityOf<mp_units::dimensionless> K, mp_units::QuantityOf<mp_units::isq::time> T>
|
||||
requires(implicitly_convertible(QM::quantity_spec, Q1::quantity_spec))
|
||||
constexpr state<Q1, Q2, Q3> state_update(const state<Q1, Q2, Q3>& predicted, QM measured, std::array<K, 3> gain,
|
||||
T interval)
|
||||
requires(implicitly_convertible(QM::quantity_spec, QP1::quantity_spec))
|
||||
[[nodiscard]] constexpr system_state<QP1, QP2, QP3> state_update(const system_state<QP1, QP2, QP3>& predicted,
|
||||
QM measured, std::array<K, 3> gain, T interval)
|
||||
{
|
||||
const auto q1 = get<0>(predicted) + get<0>(gain) * (measured - get<0>(predicted));
|
||||
const auto q2 = get<1>(predicted) + get<1>(gain) * (measured - get<0>(predicted)) / interval;
|
||||
const auto q3 = get<2>(predicted) + get<2>(gain) * (measured - get<0>(predicted)) / (interval * interval / 2);
|
||||
return {q1, q2, q3};
|
||||
const auto qp1 = fma(get<0>(gain), measured - get<0>(predicted), get<0>(predicted));
|
||||
const auto qp2 = fma(get<1>(gain), (measured - get<0>(predicted)) / interval, get<1>(predicted));
|
||||
const auto qp3 = fma(get<2>(gain), (measured - get<0>(predicted)) / (interval * interval / 2), get<2>(predicted));
|
||||
return system_state<QP1, QP2, QP3>{qp1, qp2, qp3};
|
||||
}
|
||||
|
||||
// covariance update
|
||||
template<mp_units::Quantity Q, mp_units::QuantityOf<mp_units::dimensionless> K>
|
||||
constexpr Q covariance_update(Q uncertainty, K gain)
|
||||
[[nodiscard]] constexpr Q covariance_update(Q uncertainty, K gain)
|
||||
{
|
||||
return (1 * mp_units::one - gain) * uncertainty;
|
||||
}
|
||||
|
||||
// state extrapolation
|
||||
template<typename Q1, typename Q2, mp_units::QuantityOf<mp_units::isq::time> T>
|
||||
constexpr state<Q1, Q2> state_extrapolation(const state<Q1, Q2>& estimated, T interval)
|
||||
template<mp_units::QuantityPoint... QPs, mp_units::QuantityPoint QP, mp_units::QuantityOf<mp_units::dimensionless> K>
|
||||
[[nodiscard]] constexpr system_state_estimate<QPs...> state_estimate_update(
|
||||
const system_state_estimate<QPs...>& previous, QP measurement, K gain)
|
||||
{
|
||||
const auto q1 = get<0>(estimated) + get<1>(estimated) * interval;
|
||||
const auto q2 = get<1>(estimated);
|
||||
return {q1, q2};
|
||||
return {state_update(previous.state(), measurement, gain), covariance_update(previous.variance(), gain)};
|
||||
};
|
||||
|
||||
|
||||
// state extrapolation
|
||||
template<typename QP1, typename QP2, mp_units::QuantityOf<mp_units::isq::time> T>
|
||||
[[nodiscard]] constexpr system_state<QP1, QP2> state_extrapolation(const system_state<QP1, QP2>& estimated, T interval)
|
||||
{
|
||||
auto to_quantity = [](const auto& qp) { return qp.quantity_ref_from(qp.point_origin); };
|
||||
const auto qp1 = fma(to_quantity(get<1>(estimated)), interval, get<0>(estimated));
|
||||
const auto qp2 = get<1>(estimated);
|
||||
return system_state<QP1, QP2>{qp1, qp2};
|
||||
}
|
||||
|
||||
template<typename Q1, typename Q2, typename Q3, mp_units::QuantityOf<mp_units::isq::time> T>
|
||||
constexpr state<Q1, Q2, Q3> state_extrapolation(const state<Q1, Q2, Q3>& estimated, T interval)
|
||||
template<typename QP1, typename QP2, typename QP3, mp_units::QuantityOf<mp_units::isq::time> T>
|
||||
[[nodiscard]] constexpr system_state<QP1, QP2, QP3> state_extrapolation(const system_state<QP1, QP2, QP3>& estimated,
|
||||
T interval)
|
||||
{
|
||||
const auto q1 = get<0>(estimated) + get<1>(estimated) * interval + get<2>(estimated) * pow<2>(interval) / 2;
|
||||
const auto q2 = get<1>(estimated) + get<2>(estimated) * interval;
|
||||
const auto q3 = get<2>(estimated);
|
||||
return {q1, q2, q3};
|
||||
auto to_quantity = [](const auto& qp) { return qp.quantity_ref_from(qp.point_origin); };
|
||||
const auto qp1 = to_quantity(get<2>(estimated)) * pow<2>(interval) / 2 +
|
||||
fma(to_quantity(get<1>(estimated)), interval, get<0>(estimated));
|
||||
const auto qp2 = fma(to_quantity(get<2>(estimated)), interval, get<1>(estimated));
|
||||
const auto qp3 = get<2>(estimated);
|
||||
return system_state<QP1, QP2, QP3>{qp1, qp2, qp3};
|
||||
}
|
||||
|
||||
// covariance extrapolation
|
||||
template<mp_units::Quantity Q>
|
||||
constexpr Q covariance_extrapolation(Q uncertainty, Q process_noise_variance)
|
||||
template<mp_units::Quantity Q1, mp_units::Quantity Q2>
|
||||
requires requires { mp_units::common_reference(Q1::reference, Q2::reference); }
|
||||
[[nodiscard]] constexpr mp_units::Quantity auto covariance_extrapolation(Q1 uncertainty, Q2 process_noise_variance)
|
||||
{
|
||||
return uncertainty + process_noise_variance;
|
||||
}
|
||||
|
||||
} // namespace kalman
|
||||
|
||||
template<typename... Qs>
|
||||
struct MP_UNITS_STD_FMT::formatter<kalman::state<Qs...>> {
|
||||
constexpr auto parse(format_parse_context& ctx)
|
||||
template<auto R, auto PO, typename Rep, typename Char>
|
||||
struct MP_UNITS_STD_FMT::formatter<mp_units::quantity_point<R, PO, Rep>, Char> :
|
||||
MP_UNITS_STD_FMT::formatter<typename mp_units::quantity_point<R, PO, Rep>::quantity_type> {
|
||||
template<typename FormatContext>
|
||||
auto format(const mp_units::quantity_point<R, PO, Rep>& qp, FormatContext& ctx) const -> decltype(ctx.out())
|
||||
{
|
||||
mp_units::detail::dynamic_specs_handler handler(specs, ctx);
|
||||
return mp_units::detail::parse_format_specs(ctx.begin(), ctx.end(), handler);
|
||||
return MP_UNITS_STD_FMT::formatter<typename mp_units::quantity_point<R, PO, Rep>::quantity_type>::format(
|
||||
qp.quantity_ref_from(qp.point_origin), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... QPs, typename Char>
|
||||
class MP_UNITS_STD_FMT::formatter<kalman::system_state<QPs...>, Char> {
|
||||
using format_specs = mp_units::detail::fill_align_width_format_specs<Char>;
|
||||
format_specs specs_{};
|
||||
std::array<std::basic_string<Char>, sizeof...(QPs)> format_str_;
|
||||
std::tuple<MP_UNITS_STD_FMT::formatter<typename QPs::quantity_type, Char>...> formatters_{};
|
||||
|
||||
template<typename Formatter>
|
||||
constexpr const Char* parse_default_spec(const Char* begin, const Char* end, Formatter& f, std::string& format_str)
|
||||
{
|
||||
if (begin == end || *begin++ != '[')
|
||||
throw MP_UNITS_STD_FMT::format_error("`default-spec` should contain a `[` character");
|
||||
auto it = begin;
|
||||
for (int nested_brackets = 0; it != end && !(*it == ']' && nested_brackets == 0); it++) {
|
||||
if (*it == '[') ++nested_brackets;
|
||||
if (*it == ']') {
|
||||
if (nested_brackets == 0) throw MP_UNITS_STD_FMT::format_error("unmatched ']' in format string");
|
||||
--nested_brackets;
|
||||
}
|
||||
}
|
||||
format_str = "{:" + std::string(begin, it) + '}';
|
||||
if (it == end) throw MP_UNITS_STD_FMT::format_error("unmatched '[' in format string");
|
||||
MP_UNITS_STD_FMT::basic_format_parse_context<Char> ctx(std::string_view(begin, it));
|
||||
auto ptr = f.parse(ctx);
|
||||
if (ptr != it) throw MP_UNITS_STD_FMT::format_error("invalid subentity format '" + std::string(begin, it) + "'");
|
||||
return ++it; // skip `]`
|
||||
}
|
||||
|
||||
template<std::size_t... Is>
|
||||
[[nodiscard]] constexpr const Char* parse_default_spec(const Char* begin, const Char* end, size_t idx,
|
||||
std::index_sequence<Is...>)
|
||||
{
|
||||
auto parse = [&](bool flag, auto& f, std::basic_string<Char>& str) {
|
||||
return flag ? parse_default_spec(begin, end, f, str) : begin;
|
||||
};
|
||||
return std::max({parse(idx == Is, std::get<Is>(formatters_), format_str_[Is])...});
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const Char* parse_defaults_specs(const Char* begin, const Char* end)
|
||||
{
|
||||
if (begin == end || *begin == '}') return begin;
|
||||
if (*begin++ != ':') throw MP_UNITS_STD_FMT::format_error("`defaults-specs` should start with a `:`");
|
||||
do {
|
||||
auto c = *begin++;
|
||||
if (c < '0' || c >= static_cast<char>('0' + sizeof...(QPs)))
|
||||
throw MP_UNITS_STD_FMT::format_error(std::string("unknown `subentity-id` token '") + c + "'");
|
||||
const size_t idx = static_cast<size_t>(c - '0');
|
||||
begin = parse_default_spec(begin, end, idx, std::index_sequence_for<QPs...>{});
|
||||
} while (begin != end && *begin != '}');
|
||||
return begin;
|
||||
}
|
||||
|
||||
template<typename OutputIt, typename FormatContext, std::size_t Idx>
|
||||
OutputIt format_system_state(OutputIt out, const kalman::system_state<QPs...>& s, FormatContext& ctx,
|
||||
std::index_sequence<Idx>) const
|
||||
{
|
||||
const std::locale locale = MP_UNITS_FMT_LOCALE(ctx.locale());
|
||||
auto f = [&](const std::basic_string<Char>& str, const mp_units::QuantityPoint auto& qp) {
|
||||
return MP_UNITS_STD_FMT::vformat_to(out, locale, str, MP_UNITS_STD_FMT::make_format_args(qp));
|
||||
};
|
||||
return f(get<Idx>(format_str_), get<Idx>(s));
|
||||
}
|
||||
|
||||
template<typename OutputIt, typename FormatContext, std::size_t Idx, std::size_t... Rest>
|
||||
requires(sizeof...(Rest) > 0)
|
||||
OutputIt format_system_state(OutputIt out, const kalman::system_state<QPs...>& s, FormatContext& ctx,
|
||||
std::index_sequence<Idx, Rest...>) const
|
||||
{
|
||||
const std::locale locale = MP_UNITS_FMT_LOCALE(ctx.locale());
|
||||
auto f = [&](const std::basic_string<Char>& str, const mp_units::QuantityPoint auto& qp) {
|
||||
return MP_UNITS_STD_FMT::vformat_to(out, locale, str, MP_UNITS_STD_FMT::make_format_args(qp));
|
||||
};
|
||||
return f(get<Idx>(format_str_), get<Idx>(s)), ((*out++ = ' ', f(get<Rest>(format_str_), get<Rest>(s))), ...);
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr formatter()
|
||||
{
|
||||
for (auto& str : format_str_) str = "{}";
|
||||
}
|
||||
|
||||
constexpr auto parse(format_parse_context& ctx) -> decltype(ctx.begin())
|
||||
{
|
||||
auto begin = ctx.begin(), end = ctx.end();
|
||||
|
||||
begin = parse_fill_align_width(ctx, begin, end, specs_, mp_units::detail::fmt_align::right);
|
||||
if (begin == end) return begin;
|
||||
|
||||
return parse_defaults_specs(begin, end);
|
||||
}
|
||||
|
||||
template<typename FormatContext>
|
||||
auto format(const kalman::state<Qs...>& s, FormatContext& ctx)
|
||||
auto format(const kalman::system_state<QPs...>& s, FormatContext& ctx) const -> decltype(ctx.out())
|
||||
{
|
||||
std::string value_buffer;
|
||||
auto to_value_buffer = std::back_inserter(value_buffer);
|
||||
if (specs.precision != -1) {
|
||||
if constexpr (sizeof...(Qs) == 1)
|
||||
MP_UNITS_STD_FMT::format_to(to_value_buffer, "{1:%.{0}Q %q}", specs.precision, kalman::get<0>(s));
|
||||
else if constexpr (sizeof...(Qs) == 2)
|
||||
MP_UNITS_STD_FMT::format_to(to_value_buffer, "{{ {1:%.{0}Q %q}, {2:%.{0}Q %q} }}", specs.precision,
|
||||
kalman::get<0>(s), kalman::get<1>(s));
|
||||
else
|
||||
MP_UNITS_STD_FMT::format_to(to_value_buffer, "{{ {1:%.{0}Q %q}, {2:%.{0}Q %q}, {3:%.{0}Q %q} }}",
|
||||
specs.precision, kalman::get<0>(s), kalman::get<1>(s), kalman::get<2>(s));
|
||||
} else {
|
||||
if constexpr (sizeof...(Qs) == 1)
|
||||
MP_UNITS_STD_FMT::format_to(to_value_buffer, "{}", kalman::get<0>(s));
|
||||
else if constexpr (sizeof...(Qs) == 2)
|
||||
MP_UNITS_STD_FMT::format_to(to_value_buffer, "{{ {}, {} }}", kalman::get<0>(s), kalman::get<1>(s));
|
||||
else
|
||||
MP_UNITS_STD_FMT::format_to(to_value_buffer, "{{ {}, {}, {} }}", kalman::get<0>(s), kalman::get<1>(s),
|
||||
kalman::get<2>(s));
|
||||
auto specs = specs_;
|
||||
mp_units::detail::handle_dynamic_spec<mp_units::detail::width_checker>(specs.width, specs.width_ref, ctx);
|
||||
|
||||
if (specs.width == 0) {
|
||||
// Avoid extra copying if width is not specified
|
||||
format_system_state(ctx.out(), s, ctx, std::index_sequence_for<QPs...>{});
|
||||
return ctx.out();
|
||||
}
|
||||
std::basic_string<Char> quantity_buffer;
|
||||
format_system_state(std::back_inserter(quantity_buffer), s, ctx, std::index_sequence_for<QPs...>{});
|
||||
|
||||
std::string global_format_buffer;
|
||||
mp_units::detail::quantity_global_format_specs<char> global_specs = {specs.fill, specs.align, specs.width};
|
||||
mp_units::detail::format_global_buffer(std::back_inserter(global_format_buffer), global_specs);
|
||||
|
||||
return MP_UNITS_STD_FMT::vformat_to(ctx.out(), global_format_buffer,
|
||||
MP_UNITS_STD_FMT::make_format_args(value_buffer));
|
||||
std::basic_string<Char> fill_align_width_format_str;
|
||||
mp_units::detail::format_global_buffer(std::back_inserter(fill_align_width_format_str), specs);
|
||||
return MP_UNITS_STD_FMT::vformat_to(ctx.out(), fill_align_width_format_str,
|
||||
MP_UNITS_STD_FMT::make_format_args(quantity_buffer));
|
||||
}
|
||||
private:
|
||||
mp_units::detail::dynamic_format_specs<char> specs;
|
||||
};
|
||||
|
||||
template<typename Q>
|
||||
struct MP_UNITS_STD_FMT::formatter<kalman::estimation<Q>> {
|
||||
constexpr auto parse(format_parse_context& ctx)
|
||||
{
|
||||
mp_units::detail::dynamic_specs_handler handler(specs, ctx);
|
||||
return mp_units::detail::parse_format_specs(ctx.begin(), ctx.end(), handler);
|
||||
}
|
||||
|
||||
template<typename FormatContext>
|
||||
auto format(kalman::estimation<Q> e, FormatContext& ctx)
|
||||
{
|
||||
mp_units::Quantity auto q = [](const Q& t) {
|
||||
if constexpr (mp_units::Quantity<Q>)
|
||||
return t;
|
||||
else
|
||||
return t.quantity_ref_from(t.point_origin);
|
||||
}(kalman::get<0>(e.state));
|
||||
|
||||
std::string value_buffer;
|
||||
auto to_value_buffer = std::back_inserter(value_buffer);
|
||||
if (specs.precision != -1) {
|
||||
MP_UNITS_STD_FMT::format_to(to_value_buffer, "{0:%.{2}Q} ± {1:%.{2}Q} {0:%q}", q, sqrt(e.uncertainty),
|
||||
specs.precision);
|
||||
} else {
|
||||
MP_UNITS_STD_FMT::format_to(to_value_buffer, "{0:%Q} ± {1:%Q} {0:%q}", q, sqrt(e.uncertainty));
|
||||
}
|
||||
|
||||
std::string global_format_buffer;
|
||||
mp_units::detail::quantity_global_format_specs<char> global_specs = {specs.fill, specs.align, specs.width};
|
||||
mp_units::detail::format_global_buffer(std::back_inserter(global_format_buffer), global_specs);
|
||||
|
||||
return MP_UNITS_STD_FMT::vformat_to(ctx.out(), global_format_buffer,
|
||||
MP_UNITS_STD_FMT::make_format_args(value_buffer));
|
||||
}
|
||||
private:
|
||||
mp_units::detail::dynamic_format_specs<char> specs;
|
||||
};
|
||||
|
@ -35,36 +35,37 @@ import mp_units;
|
||||
|
||||
using namespace mp_units;
|
||||
|
||||
void print_header(const kalman::State auto& initial)
|
||||
void print_header(const kalman::SystemState auto& initial)
|
||||
{
|
||||
std::cout << MP_UNITS_STD_FMT::format("Initial: {}\n", initial);
|
||||
std::cout << MP_UNITS_STD_FMT::format("{:>2} | {:>9} | {:>8} | {:>14} | {:>14}\n", "N", "Gain", "Measured",
|
||||
"Curr. Estimate", "Next Estimate");
|
||||
}
|
||||
|
||||
void print(auto iteration, QuantityOf<dimensionless> auto gain, Quantity auto measured,
|
||||
const kalman::State auto& current, const kalman::State auto& next)
|
||||
void print(auto iteration, QuantityOf<dimensionless> auto gain, QuantityPoint auto measured,
|
||||
const kalman::SystemState auto& current, const kalman::SystemState auto& next)
|
||||
{
|
||||
std::cout << MP_UNITS_STD_FMT::format("{:2} | {:9} | {:8} | {:14} | {:14}\n", iteration, gain, measured, current,
|
||||
next);
|
||||
std::cout << MP_UNITS_STD_FMT::format("{:2} | {:9:N[.2f]} | {:8} | {:14:0[:N[.2f]]} | {:14:0[:N[.2f]]}\n", iteration,
|
||||
gain, measured, current, next);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace mp_units::si::unit_symbols;
|
||||
using state = kalman::state<quantity<isq::mass[g]>>;
|
||||
using state = kalman::system_state<quantity_point<isq::mass[g]>>;
|
||||
using qp = quantity_point<isq::mass[g]>;
|
||||
|
||||
const state initial = {1 * kg};
|
||||
const std::array measurements = {1'030 * g, 989 * g, 1'017 * g, 1'009 * g, 1'013 * g,
|
||||
979 * g, 1'008 * g, 1'042 * g, 1'012 * g, 1'011 * g};
|
||||
const state initial_guess{qp{1 * kg}};
|
||||
const std::array measurements = {qp{996 * g}, qp{994 * g}, qp{1021 * g}, qp{1000 * g}, qp{1002 * g},
|
||||
qp{1010 * g}, qp{983 * g}, qp{971 * g}, qp{993 * g}, qp{1023 * g}};
|
||||
|
||||
print_header(initial);
|
||||
state next = initial;
|
||||
for (int index = 1; const auto& v : measurements) {
|
||||
const auto& previous = next;
|
||||
const auto gain = 1. / index * one;
|
||||
const auto current = state_update(previous, v, gain);
|
||||
print_header(initial_guess);
|
||||
state next = initial_guess;
|
||||
for (int index = 1; const auto& measurement : measurements) {
|
||||
const state& previous = next;
|
||||
const quantity gain = 1. / index * one;
|
||||
const state current = state_update(previous, measurement, gain);
|
||||
next = current;
|
||||
print(index++, gain, v, current, next);
|
||||
print(index++, gain, measurement, current, next);
|
||||
}
|
||||
}
|
||||
|
@ -39,36 +39,38 @@ inline constexpr bool mp_units::is_vector<T> = true;
|
||||
|
||||
using namespace mp_units;
|
||||
|
||||
void print_header(const kalman::State auto& initial)
|
||||
void print_header(const kalman::SystemState auto& initial)
|
||||
{
|
||||
std::cout << MP_UNITS_STD_FMT::format("Initial: {}\n", initial);
|
||||
std::cout << MP_UNITS_STD_FMT::format("{:>2} | {:>8} | {:>23} | {:>23}\n", "N", "Measured", "Curr. Estimate",
|
||||
"Next Estimate");
|
||||
}
|
||||
|
||||
void print(auto iteration, Quantity auto measured, const kalman::State auto& current, const kalman::State auto& next)
|
||||
void print(auto iteration, QuantityPoint auto measured, const kalman::SystemState auto& current,
|
||||
const kalman::SystemState auto& next)
|
||||
{
|
||||
std::cout << MP_UNITS_STD_FMT::format("{:2} | {:8} | {:.1} | {:.1}\n", iteration, measured, current, next);
|
||||
std::cout << MP_UNITS_STD_FMT::vformat("{:2} | {:8} | {:23:0[:N[.2f]]1[:N[.2f]]} | {:23:0[:N[.2f]]1[:N[.2f]]}\n",
|
||||
MP_UNITS_STD_FMT::make_format_args(iteration, measured, current, next));
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace mp_units::si::unit_symbols;
|
||||
using state = kalman::state<quantity<isq::position_vector[m]>, quantity<isq::velocity[m / s]>>;
|
||||
using qp = quantity_point<isq::position_vector[m]>;
|
||||
using state = kalman::system_state<qp, quantity_point<isq::velocity[m / s]>>;
|
||||
|
||||
const auto interval = isq::duration(5 * s);
|
||||
const state initial = {30 * km, 40 * m / s};
|
||||
const quantity<isq::position_vector[m], int> measurements[] = {30'110 * m, 30'265 * m, 30'740 * m, 30'750 * m,
|
||||
31'135 * m, 31'015 * m, 31'180 * m, 31'610 * m,
|
||||
31'960 * m, 31'865 * m};
|
||||
const quantity interval = isq::duration(5 * s);
|
||||
const state initial{qp{30 * km}, quantity_point{40 * m / s}};
|
||||
const std::array measurements = {qp{30'171 * m}, qp{30'353 * m}, qp{30'756 * m}, qp{30'799 * m}, qp{31'018 * m},
|
||||
qp{31'278 * m}, qp{31'276 * m}, qp{31'379 * m}, qp{31'748 * m}, qp{32'175 * m}};
|
||||
std::array gain = {0.2 * one, 0.1 * one};
|
||||
|
||||
print_header(initial);
|
||||
state next = state_extrapolation(initial, interval);
|
||||
for (int index = 1; const auto& measured : measurements) {
|
||||
const auto& previous = next;
|
||||
const auto current = state_update(previous, measured, gain, interval);
|
||||
for (int index = 1; const auto& measurement : measurements) {
|
||||
const state& previous = next;
|
||||
const state current = state_update(previous, measurement, gain, interval);
|
||||
next = state_extrapolation(current, interval);
|
||||
print(index++, measured, current, next);
|
||||
print(index++, measurement, current, next);
|
||||
}
|
||||
}
|
||||
|
@ -39,36 +39,38 @@ inline constexpr bool mp_units::is_vector<T> = true;
|
||||
|
||||
using namespace mp_units;
|
||||
|
||||
void print_header(const kalman::State auto& initial)
|
||||
void print_header(const kalman::SystemState auto& initial)
|
||||
{
|
||||
std::cout << MP_UNITS_STD_FMT::format("Initial: {}\n", initial);
|
||||
std::cout << MP_UNITS_STD_FMT::format("{:>2} | {:>8} | {:>24} | {:>24}\n", "N", "Measured", "Curr. Estimate",
|
||||
std::cout << MP_UNITS_STD_FMT::format("{:>2} | {:>8} | {:>23} | {:>23}\n", "N", "Measured", "Curr. Estimate",
|
||||
"Next Estimate");
|
||||
}
|
||||
|
||||
void print(auto iteration, Quantity auto measured, const kalman::State auto& current, const kalman::State auto& next)
|
||||
void print(auto iteration, QuantityPoint auto measured, const kalman::SystemState auto& current,
|
||||
const kalman::SystemState auto& next)
|
||||
{
|
||||
std::cout << MP_UNITS_STD_FMT::format("{:2} | {:8} | {:>24.1} | {:>24.1}\n", iteration, measured, current, next);
|
||||
std::cout << MP_UNITS_STD_FMT::format("{:2} | {:8} | {:23:0[:N[.2f]]1[:N[.2f]]} | {:23:0[:N[.2f]]1[:N[.2f]]}\n",
|
||||
iteration, measured, current, next);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace mp_units::si::unit_symbols;
|
||||
using state = kalman::state<quantity<isq::position_vector[m]>, quantity<isq::velocity[m / s]>>;
|
||||
using qp = quantity_point<isq::position_vector[m]>;
|
||||
using state = kalman::system_state<qp, quantity_point<isq::velocity[m / s]>>;
|
||||
|
||||
const auto interval = isq::duration(5 * s);
|
||||
const state initial = {30 * km, 50 * m / s};
|
||||
const quantity<isq::position_vector[m], int> measurements[] = {30'160 * m, 30'365 * m, 30'890 * m, 31'050 * m,
|
||||
31'785 * m, 32'215 * m, 33'130 * m, 34'510 * m,
|
||||
36'010 * m, 37'265 * m};
|
||||
const quantity interval = isq::duration(5 * s);
|
||||
const state initial{qp{30 * km}, quantity_point{50 * m / s}};
|
||||
const std::array measurements = {qp{30'221 * m}, qp{30'453 * m}, qp{30'906 * m}, qp{30'999 * m}, qp{31'368 * m},
|
||||
qp{31'978 * m}, qp{32'526 * m}, qp{33'379 * m}, qp{34'698 * m}, qp{36'275 * m}};
|
||||
std::array gain = {0.2 * one, 0.1 * one};
|
||||
|
||||
print_header(initial);
|
||||
state next = state_extrapolation(initial, interval);
|
||||
for (int index = 1; const auto& measured : measurements) {
|
||||
const auto& previous = next;
|
||||
const auto current = state_update(previous, measured, gain, interval);
|
||||
for (int index = 1; const auto& measurement : measurements) {
|
||||
const state& previous = next;
|
||||
const state current = state_update(previous, measurement, gain, interval);
|
||||
next = state_extrapolation(current, interval);
|
||||
print(index++, measured, current, next);
|
||||
print(index++, measurement, current, next);
|
||||
}
|
||||
}
|
||||
|
@ -39,37 +39,40 @@ inline constexpr bool mp_units::is_vector<T> = true;
|
||||
|
||||
using namespace mp_units;
|
||||
|
||||
void print_header(const kalman::State auto& initial)
|
||||
void print_header(const kalman::SystemState auto& initial)
|
||||
{
|
||||
std::cout << MP_UNITS_STD_FMT::format("Initial: {}\n", initial);
|
||||
std::cout << MP_UNITS_STD_FMT::format("{:>2} | {:>8} | {:>35} | {:>35}\n", "N", "Measured", "Curr. Estimate",
|
||||
"Next Estimate");
|
||||
}
|
||||
|
||||
void print(auto iteration, Quantity auto measured, const kalman::State auto& current, const kalman::State auto& next)
|
||||
void print(auto iteration, QuantityPoint auto measured, const kalman::SystemState auto& current,
|
||||
const kalman::SystemState auto& next)
|
||||
{
|
||||
std::cout << MP_UNITS_STD_FMT::format("{:2} | {:8} | {:>35.1} | {:>35.1}\n", iteration, measured, current, next);
|
||||
std::cout << MP_UNITS_STD_FMT::format(
|
||||
"{:2} | {:8} | {:35:0[:N[.2f]]1[:N[.2f]]2[:N[.2f]]} | {:35:0[:N[.2f]]1[:N[.2f]]2[:N[.2f]]}\n", iteration, measured,
|
||||
current, next);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace mp_units::si::unit_symbols;
|
||||
using state = kalman::state<quantity<isq::position_vector[m]>, quantity<isq::velocity[m / s]>,
|
||||
quantity<isq::acceleration[m / s2]>>;
|
||||
const auto interval = isq::duration(5. * s);
|
||||
const state initial = {30 * km, 50 * m / s, 0 * m / s2};
|
||||
using qp = quantity_point<isq::position_vector[m]>;
|
||||
using state =
|
||||
kalman::system_state<qp, quantity_point<isq::velocity[m / s]>, quantity_point<isq::acceleration[m / s2]>>;
|
||||
|
||||
const quantity<isq::position_vector[m], int> measurements[] = {30'160 * m, 30'365 * m, 30'890 * m, 31'050 * m,
|
||||
31'785 * m, 32'215 * m, 33'130 * m, 34'510 * m,
|
||||
36'010 * m, 37'265 * m};
|
||||
const quantity interval = isq::duration(5. * s);
|
||||
const state initial{qp{30 * km}, quantity_point{50 * m / s}, quantity_point{0 * m / s2}};
|
||||
const std::array measurements = {qp{30'221 * m}, qp{30'453 * m}, qp{30'906 * m}, qp{30'999 * m}, qp{31'368 * m},
|
||||
qp{31'978 * m}, qp{32'526 * m}, qp{33'379 * m}, qp{34'698 * m}, qp{36'275 * m}};
|
||||
std::array gain = {0.5 * one, 0.4 * one, 0.1 * one};
|
||||
|
||||
print_header(initial);
|
||||
state next = state_extrapolation(initial, interval);
|
||||
for (int index = 1; const auto& measured : measurements) {
|
||||
const auto& previous = next;
|
||||
const auto current = state_update(previous, measured, gain, interval);
|
||||
for (int index = 1; const auto& measurement : measurements) {
|
||||
const state& previous = next;
|
||||
const state current = state_update(previous, measurement, gain, interval);
|
||||
next = state_extrapolation(current, interval);
|
||||
print(index++, measured, current, next);
|
||||
print(index++, measurement, current, next);
|
||||
}
|
||||
}
|
||||
|
@ -36,45 +36,45 @@ import mp_units;
|
||||
|
||||
using namespace mp_units;
|
||||
|
||||
template<Quantity Q>
|
||||
void print_header(kalman::estimation<Q> initial)
|
||||
template<QuantityPoint QP>
|
||||
void print_header(kalman::system_state_estimate<QP> initial)
|
||||
{
|
||||
std::cout << MP_UNITS_STD_FMT::format("Initial: {}\n", initial);
|
||||
std::cout << MP_UNITS_STD_FMT::format("{:>2} | {:>5} | {:>8} | {:>16} | {:>16}\n", "N", "Gain", "Measured",
|
||||
std::cout << MP_UNITS_STD_FMT::format("Initial: {} {}\n", initial.state(), initial.variance());
|
||||
std::cout << MP_UNITS_STD_FMT::format("{:>2} | {:>8} | {:>5} | {:>16} | {:>16}\n", "N", "Measured", "Gain",
|
||||
"Curr. Estimate", "Next Estimate");
|
||||
}
|
||||
|
||||
template<Quantity Q, QuantityOf<dimensionless> K>
|
||||
void print(auto iteration, K gain, Q measured, kalman::estimation<Q> current, kalman::estimation<Q> next)
|
||||
template<QuantityPoint QP, QuantityOf<dimensionless> K>
|
||||
void print(auto iteration, QP measured, K gain, kalman::system_state_estimate<QP> current,
|
||||
kalman::system_state_estimate<QP> next)
|
||||
{
|
||||
std::cout << MP_UNITS_STD_FMT::format("{:2} | {:5%.2Q} | {:8} | {:>16.2} | {:>16.2}\n", iteration, gain, measured,
|
||||
current, next);
|
||||
std::cout << MP_UNITS_STD_FMT::format(
|
||||
"{:2} | {:8} | {:5:N[.2f]} | {:6:0[:N[.2f]]} {:8:N[.2f]} | {:6:0[:N[.2f]]} {:8:N[.2f]}\n", iteration, measured,
|
||||
gain, current.state(), current.variance(), next.state(), next.variance());
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace kalman;
|
||||
using namespace mp_units::si::unit_symbols;
|
||||
using qp = quantity_point<isq::height[m]>;
|
||||
using estimate = kalman::system_state_estimate<qp>;
|
||||
using state = estimate::state_type;
|
||||
|
||||
const estimation initial = {state{isq::height(60. * m)}, pow<2>(isq::height(15. * m))};
|
||||
const quantity<isq::height[m]> measurements[] = {48.54 * m, 47.11 * m, 55.01 * m, 55.15 * m, 49.89 * m,
|
||||
40.85 * m, 46.72 * m, 50.05 * m, 51.27 * m, 49.95 * m};
|
||||
const auto measurement_uncertainty = pow<2>(isq::height(5. * m));
|
||||
const estimate initial{state{qp{60. * m}}, 15. * m};
|
||||
const std::array measurements = {qp{49.03 * m}, qp{48.44 * m}, qp{55.21 * m}, qp{49.98 * m}, qp{50.6 * m},
|
||||
qp{52.61 * m}, qp{45.87 * m}, qp{42.64 * m}, qp{48.26 * m}, qp{55.84 * m}};
|
||||
const quantity measurement_error = isq::height(5. * m);
|
||||
const quantity measurement_variance = pow<2>(measurement_error);
|
||||
|
||||
auto update = [=]<Quantity Q>(const estimation<Q>& previous, const Q& measurement,
|
||||
QuantityOf<dimensionless> auto gain) {
|
||||
return estimation{state_update(previous.state, measurement, gain), covariance_update(previous.uncertainty, gain)};
|
||||
};
|
||||
|
||||
auto predict = []<Quantity Q>(const estimation<Q>& current) { return current; };
|
||||
auto predict = [](const estimate& current) { return current; };
|
||||
|
||||
print_header(initial);
|
||||
estimation next = predict(initial);
|
||||
for (int index = 1; const auto& measured : measurements) {
|
||||
const auto& previous = next;
|
||||
const auto gain = kalman_gain(previous.uncertainty, measurement_uncertainty);
|
||||
const estimation current = update(previous, measured, gain);
|
||||
estimate next = predict(initial);
|
||||
for (int index = 1; const auto& measurement : measurements) {
|
||||
const estimate& previous = next;
|
||||
const quantity gain = kalman::kalman_gain(previous.variance(), measurement_variance);
|
||||
const estimate current = state_estimate_update(previous, measurement, gain);
|
||||
next = predict(current);
|
||||
print(index++, gain, measured, current, next);
|
||||
print(index++, measurement, gain, current, next);
|
||||
}
|
||||
}
|
||||
|
@ -27,62 +27,59 @@
|
||||
import mp_units;
|
||||
#else
|
||||
#include <mp-units/format.h>
|
||||
#include <mp-units/framework/quantity_point.h>
|
||||
#include <mp-units/math.h>
|
||||
#include <mp-units/quantity_point.h>
|
||||
#include <mp-units/systems/isq/thermodynamics.h>
|
||||
#include <mp-units/systems/si/si.h>
|
||||
#include <mp-units/systems/si.h>
|
||||
#endif
|
||||
|
||||
// Based on: https://www.kalmanfilter.net/kalman1d.html#ex6
|
||||
// Based on: https://www.kalmanfilter.net/kalman1d_pn.html#ex6
|
||||
|
||||
using namespace mp_units;
|
||||
|
||||
template<QuantityPoint QP>
|
||||
void print_header(kalman::estimation<QP> initial)
|
||||
void print_header(kalman::system_state_estimate<QP> initial)
|
||||
{
|
||||
std::cout << MP_UNITS_STD_FMT::format("Initial: {}\n", initial);
|
||||
std::cout << MP_UNITS_STD_FMT::format("{:>2} | {:>7} | {:>10} | {:>18} | {:>18}\n", "N", "Gain", "Measured",
|
||||
std::cout << MP_UNITS_STD_FMT::format("Initial: {}\n", initial.state(), initial.variance());
|
||||
std::cout << MP_UNITS_STD_FMT::format("{:>2} | {:>10} | {:>7} | {:>22} | {:>22}\n", "N", "Measured", "Gain",
|
||||
"Curr. Estimate", "Next Estimate");
|
||||
}
|
||||
|
||||
template<QuantityPoint QP, QuantityOf<dimensionless> K>
|
||||
void print(auto iteration, K gain, QP measured, kalman::estimation<QP> current, kalman::estimation<QP> next)
|
||||
void print(auto iteration, QP measured, K gain, kalman::system_state_estimate<QP> current,
|
||||
kalman::system_state_estimate<QP> next)
|
||||
{
|
||||
std::cout << MP_UNITS_STD_FMT::format("{:2} | {:7%.4Q} | {:10%.3Q %q} | {:>18.3} | {:>18.3}\n", iteration, gain,
|
||||
measured.quantity_ref_from(QP::point_origin), current, next);
|
||||
std::cout << MP_UNITS_STD_FMT::format(
|
||||
"{:2} | {:10} | {:7:N[.4f]} | {:10:0[:N[.3f]]} {:11:N[.4f]} | {:10:0[:N[.3f]]} {:11:N[.4f]}\n", iteration, measured,
|
||||
gain, current.state(), current.variance(), next.state(), next.variance());
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
constexpr auto deg_C = isq::Celsius_temperature[si::degree_Celsius];
|
||||
using namespace mp_units::si::unit_symbols;
|
||||
using qp = quantity_point<isq::Celsius_temperature[deg_C]>;
|
||||
using estimate = kalman::system_state_estimate<qp>;
|
||||
using state = estimate::state_type;
|
||||
|
||||
using namespace kalman;
|
||||
const quantity process_noise_variance = 0.0001 * pow<2>(deg_C);
|
||||
const estimate initial{state{qp{60. * deg_C}}, 100. * deg_C};
|
||||
const std::array measurements = {qp{49.986 * deg_C}, qp{49.963 * deg_C}, qp{50.09 * deg_C}, qp{50.001 * deg_C},
|
||||
qp{50.018 * deg_C}, qp{50.05 * deg_C}, qp{49.938 * deg_C}, qp{49.858 * deg_C},
|
||||
qp{49.965 * deg_C}, qp{50.114 * deg_C}};
|
||||
const quantity measurement_error = 0.1 * deg_C;
|
||||
const quantity measurement_variance = pow<2>(measurement_error);
|
||||
|
||||
const auto process_noise_variance = 0.0001 * (deg_C * deg_C);
|
||||
const estimation initial = {state{si::ice_point + 10. * deg_C}, pow<2>(100. * deg_C)};
|
||||
const std::array measurements = {si::ice_point + 49.95 * deg_C, si::ice_point + 49.967 * deg_C,
|
||||
si::ice_point + 50.1 * deg_C, si::ice_point + 50.106 * deg_C,
|
||||
si::ice_point + 49.992 * deg_C, si::ice_point + 49.819 * deg_C,
|
||||
si::ice_point + 49.933 * deg_C, si::ice_point + 50.007 * deg_C,
|
||||
si::ice_point + 50.023 * deg_C, si::ice_point + 49.99 * deg_C};
|
||||
const auto measurement_uncertainty = pow<2>(0.1 * deg_C);
|
||||
|
||||
auto update = [=]<QuantityPoint QP>(const estimation<QP>& previous, const QP& meassurement,
|
||||
QuantityOf<dimensionless> auto gain) {
|
||||
return estimation{state_update(previous.state, meassurement, gain), covariance_update(previous.uncertainty, gain)};
|
||||
};
|
||||
|
||||
auto predict = [=]<QuantityPoint QP>(const estimation<QP>& current) {
|
||||
return estimation{current.state, covariance_extrapolation(current.uncertainty, process_noise_variance)};
|
||||
auto predict = [=](const estimate& current) {
|
||||
return estimate{current.state(), kalman::covariance_extrapolation(current.variance(), process_noise_variance)};
|
||||
};
|
||||
|
||||
print_header(initial);
|
||||
estimation next = predict(initial);
|
||||
for (int index = 1; const auto& m : measurements) {
|
||||
const auto& previous = next;
|
||||
const auto gain = kalman_gain(previous.uncertainty, measurement_uncertainty);
|
||||
const estimation current = update(previous, m, gain);
|
||||
estimate next = predict(initial);
|
||||
for (int index = 1; const auto& measurement : measurements) {
|
||||
const estimate& previous = next;
|
||||
const quantity gain = kalman::kalman_gain(previous.variance(), measurement_variance);
|
||||
const estimate current = state_estimate_update(previous, measurement, gain);
|
||||
next = predict(current);
|
||||
print(index++, gain, m, current, next);
|
||||
print(index++, measurement, gain, current, next);
|
||||
}
|
||||
}
|
||||
|
@ -27,62 +27,59 @@
|
||||
import mp_units;
|
||||
#else
|
||||
#include <mp-units/format.h>
|
||||
#include <mp-units/framework/quantity_point.h>
|
||||
#include <mp-units/math.h>
|
||||
#include <mp-units/quantity_point.h>
|
||||
#include <mp-units/systems/isq/thermodynamics.h>
|
||||
#include <mp-units/systems/si/si.h>
|
||||
#include <mp-units/systems/si.h>
|
||||
#endif
|
||||
|
||||
// Based on: https://www.kalmanfilter.net/kalman1d.html#ex7
|
||||
// Based on: https://www.kalmanfilter.net/kalman1d_pn.html#ex7
|
||||
|
||||
using namespace mp_units;
|
||||
|
||||
template<QuantityPoint QP>
|
||||
void print_header(kalman::estimation<QP> initial)
|
||||
void print_header(kalman::system_state_estimate<QP> initial)
|
||||
{
|
||||
std::cout << MP_UNITS_STD_FMT::format("Initial: {}\n", initial);
|
||||
std::cout << MP_UNITS_STD_FMT::format("{:>2} | {:>7} | {:>10} | {:>18} | {:>18}\n", "N", "Gain", "Measured",
|
||||
std::cout << MP_UNITS_STD_FMT::format("Initial: {}\n", initial.state(), initial.variance());
|
||||
std::cout << MP_UNITS_STD_FMT::format("{:>2} | {:>10} | {:>7} | {:>22} | {:>22}\n", "N", "Measured", "Gain",
|
||||
"Curr. Estimate", "Next Estimate");
|
||||
}
|
||||
|
||||
template<QuantityPoint QP, QuantityOf<dimensionless> K>
|
||||
void print(auto iteration, K gain, QP measured, kalman::estimation<QP> current, kalman::estimation<QP> next)
|
||||
void print(auto iteration, QP measured, K gain, kalman::system_state_estimate<QP> current,
|
||||
kalman::system_state_estimate<QP> next)
|
||||
{
|
||||
std::cout << MP_UNITS_STD_FMT::format("{:2} | {:7%.4Q} | {:10%.3Q %q} | {:>18.3} | {:>18.3}\n", iteration, gain,
|
||||
measured.quantity_ref_from(QP::point_origin), current, next);
|
||||
std::cout << MP_UNITS_STD_FMT::format(
|
||||
"{:2} | {:10} | {:7:N[.4f]} | {:10:0[:N[.3f]]} {:11:N[.4f]} | {:10:0[:N[.3f]]} {:11:N[.4f]}\n", iteration, measured,
|
||||
gain, current.state(), current.variance(), next.state(), next.variance());
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
constexpr auto deg_C = isq::Celsius_temperature[si::degree_Celsius];
|
||||
using namespace mp_units::si::unit_symbols;
|
||||
using qp = quantity_point<isq::Celsius_temperature[deg_C]>;
|
||||
using estimate = kalman::system_state_estimate<qp>;
|
||||
using state = estimate::state_type;
|
||||
|
||||
using namespace kalman;
|
||||
const quantity process_noise_variance = 0.0001 * pow<2>(deg_C);
|
||||
const estimate initial{state{qp{10. * deg_C}}, 100. * deg_C};
|
||||
const std::array measurements = {qp{50.486 * deg_C}, qp{50.963 * deg_C}, qp{51.597 * deg_C}, qp{52.001 * deg_C},
|
||||
qp{52.518 * deg_C}, qp{53.05 * deg_C}, qp{53.438 * deg_C}, qp{53.858 * deg_C},
|
||||
qp{54.465 * deg_C}, qp{55.114 * deg_C}};
|
||||
const quantity measurement_error = 0.1 * deg_C;
|
||||
const quantity measurement_variance = pow<2>(measurement_error);
|
||||
|
||||
const auto process_noise_variance = 0.0001 * (deg_C * deg_C);
|
||||
const estimation initial = {state{si::ice_point + 10. * deg_C}, pow<2>(100. * deg_C)};
|
||||
const std::array measurements = {si::ice_point + 50.45 * deg_C, si::ice_point + 50.967 * deg_C,
|
||||
si::ice_point + 51.6 * deg_C, si::ice_point + 52.106 * deg_C,
|
||||
si::ice_point + 52.492 * deg_C, si::ice_point + 52.819 * deg_C,
|
||||
si::ice_point + 53.433 * deg_C, si::ice_point + 54.007 * deg_C,
|
||||
si::ice_point + 54.523 * deg_C, si::ice_point + 54.99 * deg_C};
|
||||
const auto measurement_uncertainty = pow<2>(0.1 * deg_C);
|
||||
|
||||
auto update = [=]<QuantityPoint QP>(const estimation<QP>& previous, const QP& meassurement,
|
||||
QuantityOf<dimensionless> auto gain) {
|
||||
return estimation{state_update(previous.state, meassurement, gain), covariance_update(previous.uncertainty, gain)};
|
||||
};
|
||||
|
||||
auto predict = [=]<QuantityPoint QP>(const estimation<QP>& current) {
|
||||
return estimation{current.state, covariance_extrapolation(current.uncertainty, process_noise_variance)};
|
||||
auto predict = [=](const estimate& current) {
|
||||
return estimate{current.state(), kalman::covariance_extrapolation(current.variance(), process_noise_variance)};
|
||||
};
|
||||
|
||||
print_header(initial);
|
||||
estimation next = predict(initial);
|
||||
for (int index = 1; const auto& m : measurements) {
|
||||
const auto& previous = next;
|
||||
const auto gain = kalman_gain(previous.uncertainty, measurement_uncertainty);
|
||||
const estimation current = update(previous, m, gain);
|
||||
estimate next = predict(initial);
|
||||
for (int index = 1; const auto& measurement : measurements) {
|
||||
const estimate& previous = next;
|
||||
const quantity gain = kalman::kalman_gain(previous.variance(), measurement_variance);
|
||||
const estimate current = state_estimate_update(previous, measurement, gain);
|
||||
next = predict(current);
|
||||
print(index++, gain, m, current, next);
|
||||
print(index++, measurement, gain, current, next);
|
||||
}
|
||||
}
|
||||
|
@ -27,62 +27,59 @@
|
||||
import mp_units;
|
||||
#else
|
||||
#include <mp-units/format.h>
|
||||
#include <mp-units/framework/quantity_point.h>
|
||||
#include <mp-units/math.h>
|
||||
#include <mp-units/quantity_point.h>
|
||||
#include <mp-units/systems/isq/thermodynamics.h>
|
||||
#include <mp-units/systems/si/si.h>
|
||||
#include <mp-units/systems/si.h>
|
||||
#endif
|
||||
|
||||
// Based on: https://www.kalmanfilter.net/kalman1d.html#ex8
|
||||
// Based on: https://www.kalmanfilter.net/kalman1d_pn.html#ex8
|
||||
|
||||
using namespace mp_units;
|
||||
|
||||
template<QuantityPoint QP>
|
||||
void print_header(kalman::estimation<QP> initial)
|
||||
void print_header(kalman::system_state_estimate<QP> initial)
|
||||
{
|
||||
std::cout << MP_UNITS_STD_FMT::format("Initial: {}\n", initial);
|
||||
std::cout << MP_UNITS_STD_FMT::format("{:>2} | {:>7} | {:>10} | {:>16} | {:>16}\n", "N", "Gain", "Measured",
|
||||
std::cout << MP_UNITS_STD_FMT::format("Initial: {}\n", initial.state(), initial.variance());
|
||||
std::cout << MP_UNITS_STD_FMT::format("{:>2} | {:>10} | {:>7} | {:>22} | {:>22}\n", "N", "Measured", "Gain",
|
||||
"Curr. Estimate", "Next Estimate");
|
||||
}
|
||||
|
||||
template<QuantityPoint QP, QuantityOf<dimensionless> K>
|
||||
void print(auto iteration, K gain, QP measured, kalman::estimation<QP> current, kalman::estimation<QP> next)
|
||||
void print(auto iteration, QP measured, K gain, kalman::system_state_estimate<QP> current,
|
||||
kalman::system_state_estimate<QP> next)
|
||||
{
|
||||
std::cout << MP_UNITS_STD_FMT::format("{:2} | {:7%.3Q} | {:10%.3Q %q} | {:>16.2} | {:>16.2}\n", iteration, gain,
|
||||
measured.quantity_ref_from(QP::point_origin), current, next);
|
||||
std::cout << MP_UNITS_STD_FMT::format(
|
||||
"{:2} | {:10} | {:7:N[.4f]} | {:10:0[:N[.3f]]} {:11:N[.4f]} | {:10:0[:N[.3f]]} {:11:N[.4f]}\n", iteration, measured,
|
||||
gain, current.state(), current.variance(), next.state(), next.variance());
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
constexpr auto deg_C = isq::Celsius_temperature[si::degree_Celsius];
|
||||
using namespace mp_units::si::unit_symbols;
|
||||
using qp = quantity_point<isq::Celsius_temperature[deg_C]>;
|
||||
using estimate = kalman::system_state_estimate<qp>;
|
||||
using state = estimate::state_type;
|
||||
|
||||
using namespace kalman;
|
||||
const quantity process_noise_variance = 0.15 * pow<2>(deg_C);
|
||||
const estimate initial{state{qp{10. * deg_C}}, 100. * deg_C};
|
||||
const std::array measurements = {qp{50.486 * deg_C}, qp{50.963 * deg_C}, qp{51.597 * deg_C}, qp{52.001 * deg_C},
|
||||
qp{52.518 * deg_C}, qp{53.05 * deg_C}, qp{53.438 * deg_C}, qp{53.858 * deg_C},
|
||||
qp{54.465 * deg_C}, qp{55.114 * deg_C}};
|
||||
const quantity measurement_error = 0.1 * deg_C;
|
||||
const quantity measurement_variance = pow<2>(measurement_error);
|
||||
|
||||
const auto process_noise_variance = 0.15 * (deg_C * deg_C);
|
||||
const estimation initial = {state{si::ice_point + 10. * deg_C}, pow<2>(100. * deg_C)};
|
||||
const std::array measurements = {si::ice_point + 50.45 * deg_C, si::ice_point + 50.967 * deg_C,
|
||||
si::ice_point + 51.6 * deg_C, si::ice_point + 52.106 * deg_C,
|
||||
si::ice_point + 52.492 * deg_C, si::ice_point + 52.819 * deg_C,
|
||||
si::ice_point + 53.433 * deg_C, si::ice_point + 54.007 * deg_C,
|
||||
si::ice_point + 54.523 * deg_C, si::ice_point + 54.99 * deg_C};
|
||||
const auto measurement_uncertainty = pow<2>(0.1 * deg_C);
|
||||
|
||||
auto update = [=]<QuantityPoint QP>(const estimation<QP>& previous, const QP& meassurement,
|
||||
QuantityOf<dimensionless> auto gain) {
|
||||
return estimation{state_update(previous.state, meassurement, gain), covariance_update(previous.uncertainty, gain)};
|
||||
};
|
||||
|
||||
auto predict = [=]<QuantityPoint QP>(const estimation<QP>& current) {
|
||||
return estimation{current.state, covariance_extrapolation(current.uncertainty, process_noise_variance)};
|
||||
auto predict = [=](const estimate& current) {
|
||||
return estimate{current.state(), kalman::covariance_extrapolation(current.variance(), process_noise_variance)};
|
||||
};
|
||||
|
||||
print_header(initial);
|
||||
estimation next = predict(initial);
|
||||
for (int index = 1; const auto& m : measurements) {
|
||||
const auto& previous = next;
|
||||
const auto gain = kalman_gain(previous.uncertainty, measurement_uncertainty);
|
||||
const estimation current = update(previous, m, gain);
|
||||
estimate next = predict(initial);
|
||||
for (int index = 1; const auto& measurement : measurements) {
|
||||
const estimate& previous = next;
|
||||
const quantity gain = kalman::kalman_gain(previous.variance(), measurement_variance);
|
||||
const estimate current = state_estimate_update(previous, measurement, gain);
|
||||
next = predict(current);
|
||||
print(index++, gain, m, current, next);
|
||||
print(index++, measurement, gain, current, next);
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,9 @@ message(STATUS "${projectPrefix}BUILD_AS_SYSTEM_HEADERS: ${${projectPrefix}BUILD
|
||||
option(${projectPrefix}BUILD_CXX_MODULES "Add C++ modules to the list of default targets" OFF)
|
||||
message(STATUS "${projectPrefix}BUILD_CXX_MODULES: ${${projectPrefix}BUILD_CXX_MODULES}")
|
||||
|
||||
option(${projectPrefix}API_FREESTANDING "Builds only freestanding part of the library" OFF)
|
||||
message(STATUS "${projectPrefix}API_FREESTANDING: ${${projectPrefix}API_FREESTANDING}")
|
||||
|
||||
if(${projectPrefix}BUILD_AS_SYSTEM_HEADERS)
|
||||
set(${projectPrefix}_AS_SYSTEM SYSTEM)
|
||||
endif()
|
||||
@ -68,13 +71,21 @@ cache_var_values(API_STRING_VIEW_RET AUTO TRUE FALSE)
|
||||
set(${projectPrefix}API_NO_CRTP AUTO CACHE STRING "Enable class definitions without CRTP idiom")
|
||||
cache_var_values(API_NO_CRTP AUTO TRUE FALSE)
|
||||
|
||||
set(${projectPrefix}API_CONTRACTS GSL-LITE CACHE STRING "Enable contract checking")
|
||||
cache_var_values(API_CONTRACTS NONE GSL-LITE MS-GSL)
|
||||
|
||||
if(${projectPrefix}API_FREESTANDING AND NOT ${projectPrefix}API_CONTRACTS STREQUAL "NONE")
|
||||
message(FATAL_ERROR "'${projectPrefix}API_CONTRACTS' should be set to 'NONE' for a freestanding build")
|
||||
endif()
|
||||
|
||||
# C++ features
|
||||
check_cxx_feature_supported(__cpp_lib_format ${projectPrefix}LIB_FORMAT_SUPPORTED)
|
||||
check_cxx_feature_supported("__cpp_constexpr >= 202211L" ${projectPrefix}STATIC_CONSTEXPR_VARS_IN_CONSTEXPR_FUNCTIONS)
|
||||
check_cxx_feature_supported(__cpp_explicit_this_parameter ${projectPrefix}EXPLICIT_THIS_PARAMETER_SUPPORTED)
|
||||
|
||||
# validate settings
|
||||
if(${projectPrefix}API_STD_FORMAT STREQUAL "TRUE"
|
||||
if(NOT ${projectPrefix}API_FREESTANDING
|
||||
AND ${projectPrefix}API_STD_FORMAT STREQUAL "TRUE"
|
||||
AND NOT
|
||||
(${projectPrefix}LIB_FORMAT_SUPPORTED
|
||||
# libc++ has a basic supports for std::format but does not set __cpp_lib_format
|
||||
|
@ -54,7 +54,7 @@ function(add_mp_units_module name target_name)
|
||||
|
||||
# validate and process arguments
|
||||
validate_unparsed(${name} ARG)
|
||||
validate_arguments_exists(${name} ARG DEPENDENCIES MODULE_INTERFACE_UNIT)
|
||||
validate_arguments_exists(${name} ARG MODULE_INTERFACE_UNIT)
|
||||
|
||||
if(${projectPrefix}TARGET_SCOPE STREQUAL INTERFACE)
|
||||
set(SCOPE "INTERFACE")
|
||||
|
@ -31,17 +31,10 @@ function(set_feature_flag name)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# find dependencies
|
||||
if(NOT TARGET gsl::gsl-lite)
|
||||
find_package(gsl-lite REQUIRED)
|
||||
endif()
|
||||
|
||||
# core library definition
|
||||
add_mp_units_module(
|
||||
core mp-units-core
|
||||
DEPENDENCIES gsl::gsl-lite
|
||||
HEADERS include/mp-units/bits/core_gmf.h
|
||||
include/mp-units/bits/fmt.h
|
||||
include/mp-units/bits/get_associated_quantity.h
|
||||
include/mp-units/bits/get_common_base.h
|
||||
include/mp-units/bits/hacks.h
|
||||
@ -79,20 +72,35 @@ add_mp_units_module(
|
||||
include/mp-units/framework/value_cast.h
|
||||
include/mp-units/compat_macros.h
|
||||
include/mp-units/concepts.h
|
||||
include/mp-units/format.h
|
||||
include/mp-units/framework.h
|
||||
include/mp-units/math.h
|
||||
include/mp-units/ostream.h
|
||||
include/mp-units/random.h
|
||||
MODULE_INTERFACE_UNIT mp-units-core.cpp
|
||||
)
|
||||
|
||||
if(NOT ${projectPrefix}API_FREESTANDING)
|
||||
target_sources(
|
||||
mp-units-core
|
||||
PUBLIC FILE_SET
|
||||
HEADERS
|
||||
BASE_DIRS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
FILES
|
||||
include/mp-units/bits/fmt.h
|
||||
include/mp-units/bits/requires_hosted.h
|
||||
include/mp-units/math.h
|
||||
include/mp-units/ostream.h
|
||||
include/mp-units/format.h
|
||||
include/mp-units/random.h
|
||||
)
|
||||
endif()
|
||||
|
||||
set_feature_flag(API_STD_FORMAT)
|
||||
set_feature_flag(API_STRING_VIEW_RET)
|
||||
set_feature_flag(API_NO_CRTP)
|
||||
|
||||
if(${projectPrefix}API_STD_FORMAT STREQUAL "FALSE" OR (${projectPrefix}API_STD_FORMAT STREQUAL "AUTO"
|
||||
AND NOT ${projectPrefix}LIB_FORMAT_SUPPORTED)
|
||||
# Text formatting
|
||||
if(NOT ${projectPrefix}API_FREESTANDING
|
||||
AND (${projectPrefix}API_STD_FORMAT STREQUAL "FALSE" OR (${projectPrefix}API_STD_FORMAT STREQUAL "AUTO"
|
||||
AND NOT ${projectPrefix}LIB_FORMAT_SUPPORTED))
|
||||
)
|
||||
if(NOT TARGET fmt::fmt)
|
||||
find_package(fmt REQUIRED)
|
||||
@ -100,6 +108,24 @@ if(${projectPrefix}API_STD_FORMAT STREQUAL "FALSE" OR (${projectPrefix}API_STD_F
|
||||
target_link_libraries(mp-units-core ${${projectPrefix}TARGET_SCOPE} fmt::fmt)
|
||||
endif()
|
||||
|
||||
# Contracts checking
|
||||
if(${projectPrefix}API_CONTRACTS STREQUAL "NONE")
|
||||
target_compile_definitions(mp-units-core ${${projectPrefix}TARGET_SCOPE} ${projectPrefix}API_CONTRACTS=0)
|
||||
elseif(${projectPrefix}API_CONTRACTS STREQUAL "GSL-LITE")
|
||||
if(NOT TARGET gsl::gsl-lite)
|
||||
find_package(gsl-lite REQUIRED)
|
||||
endif()
|
||||
target_link_libraries(mp-units-core ${${projectPrefix}TARGET_SCOPE} gsl::gsl-lite)
|
||||
target_compile_definitions(mp-units-core ${${projectPrefix}TARGET_SCOPE} ${projectPrefix}API_CONTRACTS=2)
|
||||
elseif(${projectPrefix}API_CONTRACTS STREQUAL "MS-GSL")
|
||||
if(NOT TARGET Microsoft.GSL::GSL)
|
||||
find_package(Microsoft.GSL REQUIRED)
|
||||
endif()
|
||||
target_link_libraries(mp-units-core ${${projectPrefix}TARGET_SCOPE} Microsoft.GSL::GSL)
|
||||
target_compile_definitions(mp-units-core ${${projectPrefix}TARGET_SCOPE} ${projectPrefix}API_CONTRACTS=3)
|
||||
endif()
|
||||
|
||||
# C++20 modules
|
||||
if(${projectPrefix}BUILD_CXX_MODULES)
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang")
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 18)
|
||||
@ -112,6 +138,7 @@ if(${projectPrefix}BUILD_CXX_MODULES)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# UTF-8 source and execution character set
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||
target_compile_options(
|
||||
mp-units-core ${${projectPrefix}TARGET_SCOPE}
|
||||
@ -119,4 +146,8 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||
)
|
||||
endif()
|
||||
|
||||
# target_compile_options(mp-units-core ${${projectPrefix}TARGET_SCOPE} "-ftime-trace")
|
||||
# Freestanding
|
||||
target_compile_definitions(
|
||||
mp-units-core ${${projectPrefix}TARGET_SCOPE}
|
||||
${projectPrefix}HOSTED=$<NOT:$<BOOL:${${projectPrefix}API_FREESTANDING}>>
|
||||
)
|
||||
|
@ -22,15 +22,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gsl/gsl-lite.hpp>
|
||||
#include <mp-units/bits/hacks.h>
|
||||
#include <mp-units/compat_macros.h>
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <compare>
|
||||
#include <concepts>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
@ -38,14 +37,20 @@
|
||||
#include <numbers>
|
||||
#include <numeric>
|
||||
#include <optional>
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <ranges>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#if MP_UNITS_HOSTED
|
||||
#include <cmath>
|
||||
#include <locale>
|
||||
#include <ostream>
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#if MP_UNITS_USE_FMTLIB
|
||||
MP_UNITS_DIAGNOSTIC_PUSH
|
||||
MP_UNITS_DIAGNOSTIC_IGNORE_UNREACHABLE
|
||||
@ -56,6 +61,8 @@ MP_UNITS_DIAGNOSTIC_POP
|
||||
#include <format>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if __cpp_lib_text_encoding
|
||||
#include <text_encoding>
|
||||
#endif
|
||||
|
@ -30,11 +30,12 @@
|
||||
// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic, cppcoreguidelines-pro-type-union-access)
|
||||
#pragma once
|
||||
|
||||
#include <mp-units/bits/module_macros.h>
|
||||
#include <mp-units/compat_macros.h>
|
||||
#include <mp-units/ext/algorithm.h>
|
||||
|
||||
#ifndef MP_UNITS_IN_MODULE_INTERFACE
|
||||
#include <gsl/gsl-lite.hpp>
|
||||
#include <array>
|
||||
#include <concepts>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
@ -45,6 +46,9 @@
|
||||
|
||||
namespace mp_units::detail {
|
||||
|
||||
// TODO the below should be exposed by the C++ Standard Library (used in our examples)
|
||||
MP_UNITS_EXPORT_BEGIN
|
||||
|
||||
enum class fmt_align : std::int8_t { none, left, right, center, numeric };
|
||||
enum class fmt_arg_id_kind : std::int8_t {
|
||||
none,
|
||||
@ -109,6 +113,8 @@ public:
|
||||
[[nodiscard]] constexpr const Char& operator[](size_t index) const { return data_[index]; }
|
||||
};
|
||||
|
||||
MP_UNITS_EXPORT_END
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_integer =
|
||||
std::is_integral_v<T> && !std::is_same_v<T, bool> && !std::is_same_v<T, char> && !std::is_same_v<T, wchar_t>;
|
||||
@ -131,24 +137,10 @@ template<typename Char>
|
||||
template<typename Int>
|
||||
[[nodiscard]] constexpr std::make_unsigned_t<Int> to_unsigned(Int value)
|
||||
{
|
||||
gsl_Expects(std::is_unsigned_v<Int> || value >= 0);
|
||||
MP_UNITS_EXPECTS(std::is_unsigned_v<Int> || value >= 0);
|
||||
return static_cast<std::make_unsigned_t<Int>>(value);
|
||||
}
|
||||
|
||||
struct width_checker {
|
||||
template<typename T>
|
||||
[[nodiscard]] constexpr unsigned long long operator()(T value) const
|
||||
{
|
||||
if constexpr (is_integer<T>) {
|
||||
if constexpr (std::numeric_limits<T>::is_signed)
|
||||
if (value < 0) MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("negative width"));
|
||||
return static_cast<unsigned long long>(value);
|
||||
}
|
||||
MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("width is not integer"));
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
template<class Handler, typename FormatArg>
|
||||
[[nodiscard]] constexpr int get_dynamic_spec(FormatArg arg)
|
||||
{
|
||||
@ -167,6 +159,9 @@ template<typename Context, typename ID>
|
||||
return arg;
|
||||
}
|
||||
|
||||
// TODO the below should be exposed by the C++ Standard Library (used in our examples)
|
||||
MP_UNITS_EXPORT_BEGIN
|
||||
|
||||
template<class Handler, typename Context>
|
||||
constexpr void handle_dynamic_spec(int& value, fmt_arg_ref<typename Context::char_type> ref, Context& ctx)
|
||||
{
|
||||
@ -184,12 +179,28 @@ constexpr void handle_dynamic_spec(int& value, fmt_arg_ref<typename Context::cha
|
||||
}
|
||||
}
|
||||
|
||||
struct width_checker {
|
||||
template<typename T>
|
||||
[[nodiscard]] constexpr unsigned long long operator()(T value) const
|
||||
{
|
||||
if constexpr (is_integer<T>) {
|
||||
if constexpr (std::numeric_limits<T>::is_signed)
|
||||
if (value < 0) MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("negative width"));
|
||||
return static_cast<unsigned long long>(value);
|
||||
}
|
||||
MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("width is not integer"));
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
MP_UNITS_EXPORT_END
|
||||
|
||||
// Parses the range [begin, end) as an unsigned integer. This function assumes
|
||||
// that the range is non-empty and the first character is a digit.
|
||||
template<typename Char>
|
||||
[[nodiscard]] constexpr int parse_nonnegative_int(const Char*& begin, const Char* end, int error_value)
|
||||
{
|
||||
gsl_Expects(begin != end && '0' <= *begin && *begin <= '9');
|
||||
MP_UNITS_EXPECTS(begin != end && '0' <= *begin && *begin <= '9');
|
||||
unsigned value = 0, prev = 0;
|
||||
auto p = begin;
|
||||
do {
|
||||
@ -250,7 +261,7 @@ template<typename Char, typename Handler>
|
||||
template<typename Char, typename Handler>
|
||||
[[nodiscard]] constexpr const Char* parse_arg_id(const Char* begin, const Char* end, Handler& handler)
|
||||
{
|
||||
gsl_Expects(begin != end);
|
||||
MP_UNITS_EXPECTS(begin != end);
|
||||
Char c = *begin;
|
||||
if (c != '}' && c != ':') return ::mp_units::detail::do_parse_arg_id(begin, end, handler);
|
||||
handler.on_auto();
|
||||
@ -292,7 +303,7 @@ template<typename Char>
|
||||
fmt_arg_ref<Char>& ref,
|
||||
MP_UNITS_STD_FMT::basic_format_parse_context<Char>& ctx)
|
||||
{
|
||||
gsl_Expects(begin != end);
|
||||
MP_UNITS_EXPECTS(begin != end);
|
||||
if ('0' <= *begin && *begin <= '9') {
|
||||
const int val = ::mp_units::detail::parse_nonnegative_int(begin, end, -1);
|
||||
if (val != -1)
|
||||
@ -329,7 +340,7 @@ template<typename Char, typename Specs>
|
||||
[[nodiscard]] constexpr const Char* parse_align(const Char* begin, const Char* end, Specs& specs,
|
||||
fmt_align default_align = fmt_align::none)
|
||||
{
|
||||
gsl_Expects(begin != end);
|
||||
MP_UNITS_EXPECTS(begin != end);
|
||||
auto align = fmt_align::none;
|
||||
auto p = begin + code_point_length(begin);
|
||||
if (end - p <= 0) p = begin;
|
||||
|
@ -59,7 +59,7 @@ template<AssociatedUnit U>
|
||||
[[nodiscard]] consteval auto get_associated_quantity_impl(U u);
|
||||
|
||||
template<AssociatedUnit U>
|
||||
using to_quantity_spec = std::remove_const_t<decltype(get_associated_quantity_impl(U{}))>;
|
||||
using to_quantity_spec = decltype(get_associated_quantity_impl(U{}));
|
||||
|
||||
template<AssociatedUnit U>
|
||||
[[nodiscard]] consteval auto get_associated_quantity_impl(U u)
|
||||
|
@ -73,6 +73,10 @@
|
||||
#define MP_UNITS_DIAGNOSTIC_IGNORE_DEPRECATED
|
||||
#endif
|
||||
|
||||
#if !defined MP_UNITS_HOSTED && defined __STDC_HOSTED__
|
||||
#define MP_UNITS_HOSTED __STDC_HOSTED__
|
||||
#endif
|
||||
|
||||
#if MP_UNITS_COMP_MSVC
|
||||
|
||||
#define MP_UNITS_TYPENAME typename
|
||||
@ -83,10 +87,26 @@
|
||||
|
||||
#endif
|
||||
|
||||
// TODO revise the below when clang-18 is released
|
||||
#if MP_UNITS_COMP_CLANG >= 18 && __cplusplus >= 202300L && !defined __cpp_explicit_this_parameter
|
||||
#if MP_UNITS_COMP_GCC
|
||||
|
||||
#define __cpp_explicit_this_parameter 202110L
|
||||
#define MP_UNITS_REMOVE_CONST(expr) std::remove_const_t<expr>
|
||||
|
||||
#else
|
||||
|
||||
#define MP_UNITS_REMOVE_CONST(expr) expr
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined __cpp_lib_ranges_to_container
|
||||
|
||||
namespace std {
|
||||
|
||||
struct from_range_t {
|
||||
explicit from_range_t() = default;
|
||||
};
|
||||
inline constexpr from_range_t from_range{};
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -24,9 +24,9 @@
|
||||
|
||||
#include <mp-units/bits/hacks.h>
|
||||
#include <mp-units/bits/module_macros.h>
|
||||
#include <mp-units/compat_macros.h>
|
||||
|
||||
#ifndef MP_UNITS_IN_MODULE_INTERFACE
|
||||
#include <gsl/gsl-lite.hpp>
|
||||
#include <compare> // IWYU pragma: export
|
||||
#include <cstdint>
|
||||
#include <numeric>
|
||||
@ -44,16 +44,16 @@ template<typename T>
|
||||
{
|
||||
constexpr std::intmax_t c = std::uintmax_t{1} << (sizeof(std::intmax_t) * 4);
|
||||
|
||||
const std::intmax_t a0 = abs(lhs) % c;
|
||||
const std::intmax_t a1 = abs(lhs) / c;
|
||||
const std::intmax_t b0 = abs(rhs) % c;
|
||||
const std::intmax_t b1 = abs(rhs) / c;
|
||||
[[maybe_unused]] const std::intmax_t a0 = abs(lhs) % c;
|
||||
[[maybe_unused]] const std::intmax_t a1 = abs(lhs) / c;
|
||||
[[maybe_unused]] const std::intmax_t b0 = abs(rhs) % c;
|
||||
[[maybe_unused]] const std::intmax_t b1 = abs(rhs) / c;
|
||||
|
||||
// overflow in multiplication
|
||||
gsl_Assert(a1 == 0 || b1 == 0);
|
||||
gsl_Assert(a0 * b1 + b0 * a1 < (c >> 1)); // NOLINT(hicpp-signed-bitwise)
|
||||
gsl_Assert(b0 * a0 <= INTMAX_MAX);
|
||||
gsl_Assert((a0 * b1 + b0 * a1) * c <= INTMAX_MAX - b0 * a0);
|
||||
MP_UNITS_ASSERT(a1 == 0 || b1 == 0);
|
||||
MP_UNITS_ASSERT(a0 * b1 + b0 * a1 < (c >> 1)); // NOLINT(hicpp-signed-bitwise)
|
||||
MP_UNITS_ASSERT(b0 * a0 <= INTMAX_MAX);
|
||||
MP_UNITS_ASSERT((a0 * b1 + b0 * a1) * c <= INTMAX_MAX - b0 * a0);
|
||||
|
||||
return lhs * rhs;
|
||||
}
|
||||
@ -72,7 +72,7 @@ MP_UNITS_EXPORT struct ratio {
|
||||
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters, google-explicit-constructor, hicpp-explicit-conversions)
|
||||
MP_UNITS_CONSTEVAL explicit(false) ratio(std::intmax_t n, std::intmax_t d = 1) : num{n}, den{d}
|
||||
{
|
||||
gsl_Expects(den != 0);
|
||||
MP_UNITS_EXPECTS(den != 0);
|
||||
if (num == 0)
|
||||
den = 1;
|
||||
else {
|
||||
@ -112,9 +112,9 @@ MP_UNITS_EXPORT struct ratio {
|
||||
if (r1.num == r2.num && r1.den == r2.den) return ratio{r1.num, r1.den};
|
||||
|
||||
// gcd(a/b,c/d) = gcd(a⋅d, c⋅b) / b⋅d
|
||||
gsl_Assert(std::numeric_limits<std::intmax_t>::max() / r1.num > r2.den);
|
||||
gsl_Assert(std::numeric_limits<std::intmax_t>::max() / r2.num > r1.den);
|
||||
gsl_Assert(std::numeric_limits<std::intmax_t>::max() / r1.den > r2.den);
|
||||
MP_UNITS_ASSERT(std::numeric_limits<std::intmax_t>::max() / r1.num > r2.den);
|
||||
MP_UNITS_ASSERT(std::numeric_limits<std::intmax_t>::max() / r2.num > r1.den);
|
||||
MP_UNITS_ASSERT(std::numeric_limits<std::intmax_t>::max() / r1.den > r2.den);
|
||||
|
||||
const std::intmax_t num = std::gcd(r1.num * r2.den, r2.num * r1.den);
|
||||
const std::intmax_t den = r1.den * r2.den;
|
||||
|
29
src/core/include/mp-units/bits/requires_hosted.h
Normal file
29
src/core/include/mp-units/bits/requires_hosted.h
Normal file
@ -0,0 +1,29 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mp-units/bits/hacks.h>
|
||||
|
||||
#if !MP_UNITS_HOSTED
|
||||
#error "This header is not available in freestanding mode."
|
||||
#endif
|
@ -23,6 +23,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <mp-units/bits/ratio.h>
|
||||
#include <mp-units/compat_macros.h>
|
||||
#include <mp-units/ext/fixed_string.h>
|
||||
#include <mp-units/ext/type_traits.h>
|
||||
#include <mp-units/framework/symbol_text.h>
|
||||
@ -100,12 +101,12 @@ constexpr Out copy(const symbol_text<N, M>& txt, text_encoding encoding, Out out
|
||||
for (const char8_t ch : txt.unicode()) *out++ = static_cast<char>(ch);
|
||||
return out;
|
||||
} else
|
||||
throw std::invalid_argument("Unicode text can't be copied to CharT output");
|
||||
MP_UNITS_THROW(std::invalid_argument("Unicode text can't be copied to CharT output"));
|
||||
} else {
|
||||
if constexpr (is_same_v<CharT, char>)
|
||||
return ::mp_units::detail::copy(txt.ascii().begin(), txt.ascii().end(), out);
|
||||
else
|
||||
throw std::invalid_argument("ASCII text can't be copied to CharT output");
|
||||
MP_UNITS_THROW(std::invalid_argument("ASCII text can't be copied to CharT output"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,15 @@
|
||||
|
||||
#endif
|
||||
|
||||
#if MP_UNITS_HOSTED
|
||||
#define MP_UNITS_THROW(expr) throw expr
|
||||
#else
|
||||
#include <cstdlib>
|
||||
#define MP_UNITS_THROW(expr) std::abort()
|
||||
#endif
|
||||
|
||||
#if MP_UNITS_HOSTED
|
||||
|
||||
#if defined MP_UNITS_API_STD_FORMAT && !MP_UNITS_API_STD_FORMAT
|
||||
|
||||
#define MP_UNITS_USE_FMTLIB 1
|
||||
@ -59,21 +68,7 @@
|
||||
#define MP_UNITS_FMT_TO_ARG_ID(arg) (arg)
|
||||
#define MP_UNITS_FMT_FROM_ARG_ID(arg) (arg)
|
||||
|
||||
// This re-uses code from fmt;
|
||||
#if FMT_EXCEPTIONS
|
||||
#if FMT_MSC_VERSION || defined(__NVCC__)
|
||||
#define MP_UNITS_THROW(x) ::fmt::detail::do_throw(x)
|
||||
#else
|
||||
#define MP_UNITS_THROW(x) throw x
|
||||
#endif
|
||||
#else
|
||||
#define MP_UNITS_THROW(x) \
|
||||
do { \
|
||||
FMT_ASSERT(false, (x).what()); \
|
||||
} while (false)
|
||||
#endif
|
||||
|
||||
#else
|
||||
#else // MP_UNITS_USE_FMTLIB
|
||||
|
||||
#if !defined __cpp_lib_format && !defined MP_UNITS_COMP_CLANG
|
||||
#error "std::formatting facility not supported"
|
||||
@ -83,10 +78,8 @@
|
||||
#define MP_UNITS_FMT_LOCALE(loc) loc
|
||||
#define MP_UNITS_FMT_TO_ARG_ID(arg) static_cast<std::size_t>(arg)
|
||||
#define MP_UNITS_FMT_FROM_ARG_ID(arg) static_cast<int>(arg)
|
||||
#define MP_UNITS_THROW(arg) throw arg
|
||||
|
||||
#endif
|
||||
|
||||
#endif // MP_UNITS_USE_FMTLIB
|
||||
|
||||
#ifndef MP_UNITS_IN_MODULE_INTERFACE
|
||||
|
||||
@ -102,5 +95,39 @@ MP_UNITS_DIAGNOSTIC_POP
|
||||
#endif
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#endif
|
||||
|
||||
#endif // MP_UNITS_HOSTED
|
||||
|
||||
#if MP_UNITS_API_CONTRACTS == 2 || __has_include(<gsl/gsl-lite.hpp>)
|
||||
|
||||
#include <gsl/gsl-lite.hpp>
|
||||
|
||||
#define MP_UNITS_EXPECTS(expr) gsl_Expects(expr)
|
||||
#define MP_UNITS_EXPECTS_DEBUG(expr) gsl_ExpectsDebug(expr)
|
||||
#define MP_UNITS_ASSERT(expr) gsl_Assert(expr)
|
||||
#define MP_UNITS_ASSERT_DEBUG(expr) gsl_AssertDebug(expr)
|
||||
|
||||
#elif MP_UNITS_API_CONTRACTS == 3 || __has_include(<gsl/gsl>)
|
||||
|
||||
#include <gsl/gsl>
|
||||
#include <cassert>
|
||||
|
||||
#define MP_UNITS_EXPECTS(expr) Expects(expr)
|
||||
#if defined NDEBUG
|
||||
#define MP_UNITS_EXPECTS_DEBUG(expr) static_cast<void>(0)
|
||||
#else
|
||||
#define MP_UNITS_EXPECTS_DEBUG(expr) Expects(expr)
|
||||
#endif
|
||||
#define MP_UNITS_ASSERT(expr) Expects(expr)
|
||||
#define MP_UNITS_ASSERT_DEBUG(expr) assert(expr)
|
||||
|
||||
#else
|
||||
|
||||
#define MP_UNITS_EXPECTS(expr) static_cast<void>(0)
|
||||
#define MP_UNITS_EXPECTS_DEBUG(expr) static_cast<void>(0)
|
||||
#define MP_UNITS_ASSERT(expr) static_cast<void>(0)
|
||||
#define MP_UNITS_ASSERT_DEBUG(expr) static_cast<void>(0)
|
||||
|
||||
#endif
|
||||
// NOLINTEND(cppcoreguidelines-macro-usage)
|
||||
|
@ -20,8 +20,9 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
// Copy-pasted C++ standard libraries to be replaced with `import std;` when available
|
||||
// `#include <algorithm.h>` is too heavy to do in every translation unit
|
||||
// Copy-pasted C++ standard libraries
|
||||
// TODO To be replaced with `import std;` when available
|
||||
// `#include <algorithm.h>` is too heavy to do in every translation unit
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -72,45 +73,6 @@ constexpr bool all_of(InputIt first, InputIt last, UnaryPred p)
|
||||
return find_if_not(first, last, p) == last;
|
||||
}
|
||||
|
||||
template<class InputIt1, class InputIt2>
|
||||
constexpr bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2)
|
||||
{
|
||||
for (; first1 != last1; ++first1, ++first2) {
|
||||
if (!(*first1 == *first2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class I1, class I2, class Cmp>
|
||||
constexpr auto lexicographical_compare_three_way(I1 first1, I1 last1, I2 first2, I2 last2, Cmp comp)
|
||||
-> decltype(comp(*first1, *first2))
|
||||
{
|
||||
using ret_t = decltype(comp(*first1, *first2));
|
||||
static_assert(std::disjunction_v<std::is_same<ret_t, std::strong_ordering>, std::is_same<ret_t, std::weak_ordering>,
|
||||
std::is_same<ret_t, std::partial_ordering>>,
|
||||
"The return type must be a comparison category type.");
|
||||
|
||||
bool exhaust1 = (first1 == last1);
|
||||
bool exhaust2 = (first2 == last2);
|
||||
MP_UNITS_DIAGNOSTIC_PUSH
|
||||
MP_UNITS_DIAGNOSTIC_IGNORE_ZERO_AS_NULLPOINTER_CONSTANT
|
||||
for (; !exhaust1 && !exhaust2; exhaust1 = (++first1 == last1), exhaust2 = (++first2 == last2))
|
||||
if (auto c = comp(*first1, *first2); c != 0) return c;
|
||||
MP_UNITS_DIAGNOSTIC_POP
|
||||
|
||||
if (!exhaust1) return std::strong_ordering::greater;
|
||||
if (!exhaust2) return std::strong_ordering::less;
|
||||
return std::strong_ordering::equal;
|
||||
}
|
||||
|
||||
template<class I1, class I2>
|
||||
constexpr auto lexicographical_compare_three_way(I1 first1, I1 last1, I2 first2, I2 last2)
|
||||
{
|
||||
return ::mp_units::detail::lexicographical_compare_three_way(first1, last1, first2, last2, std::compare_three_way());
|
||||
}
|
||||
|
||||
template<class ForwardIt>
|
||||
constexpr ForwardIt max_element(ForwardIt first, ForwardIt last)
|
||||
{
|
||||
@ -170,4 +132,18 @@ constexpr OutputIt copy(InputIt first, InputIt last, OutputIt d_first)
|
||||
return d_first;
|
||||
}
|
||||
|
||||
template<class ForwardIt1, class ForwardIt2>
|
||||
constexpr void iter_swap(ForwardIt1 a, ForwardIt2 b)
|
||||
{
|
||||
using std::swap;
|
||||
swap(*a, *b);
|
||||
}
|
||||
|
||||
template<class ForwardIt1, class ForwardIt2>
|
||||
constexpr ForwardIt2 swap_ranges(ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2)
|
||||
{
|
||||
for (; first1 != last1; ++first1, ++first2) iter_swap(first1, first2);
|
||||
return first2;
|
||||
}
|
||||
|
||||
} // namespace mp_units::detail
|
||||
|
@ -26,18 +26,20 @@
|
||||
// NOLINTBEGIN(*-avoid-c-arrays)
|
||||
#pragma once
|
||||
|
||||
// TODO use <algorithm> when moved to C++20 modules (parsing takes too long for each translation unit)
|
||||
#include <mp-units/bits/hacks.h> // IWYU pragma: keep
|
||||
#include <mp-units/bits/module_macros.h>
|
||||
#include <mp-units/compat_macros.h> // IWYU pragma: keep
|
||||
#include <mp-units/ext/algorithm.h>
|
||||
#include <mp-units/ext/type_traits.h>
|
||||
|
||||
#ifndef MP_UNITS_IN_MODULE_INTERFACE
|
||||
#include <gsl/gsl-lite.hpp>
|
||||
#include <compare> // IWYU pragma: export
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <ostream>
|
||||
#include <ranges>
|
||||
#include <string_view>
|
||||
#if MP_UNITS_HOSTED
|
||||
#include <ostream>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
MP_UNITS_EXPORT
|
||||
@ -49,121 +51,247 @@ namespace mp_units {
|
||||
* @tparam CharT Character type to be used by the string
|
||||
* @tparam N The size of the string
|
||||
*/
|
||||
template<typename CharT, std::size_t N>
|
||||
struct basic_fixed_string {
|
||||
CharT data_[N + 1] = {};
|
||||
template<typename CharT, std::size_t N, typename Traits = std::char_traits<CharT>>
|
||||
class basic_fixed_string {
|
||||
public:
|
||||
CharT data_[N + 1] = {}; // exposition only
|
||||
|
||||
// types
|
||||
using traits_type = Traits;
|
||||
using value_type = CharT;
|
||||
using pointer = CharT*;
|
||||
using const_pointer = const CharT*;
|
||||
using reference = CharT&;
|
||||
using const_reference = const CharT&;
|
||||
using const_iterator = const CharT*;
|
||||
using pointer = value_type*;
|
||||
using const_pointer = const value_type*;
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
using const_iterator = const value_type*;
|
||||
using iterator = const_iterator;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
using reverse_iterator = const_reverse_iterator;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
constexpr explicit(false) basic_fixed_string(const CharT (&txt)[N + 1]) noexcept
|
||||
// construction and assignment
|
||||
template<std::convertible_to<CharT>... Chars>
|
||||
requires(sizeof...(Chars) == N) && (... && !std::is_pointer_v<Chars>)
|
||||
constexpr explicit basic_fixed_string(Chars... chars) noexcept : data_{chars..., CharT{}}
|
||||
{
|
||||
gsl_Expects(txt[N] == CharT{});
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
consteval explicit(false) basic_fixed_string(const CharT (&txt)[N + 1]) noexcept
|
||||
{
|
||||
MP_UNITS_EXPECTS(txt[N] == CharT{});
|
||||
for (std::size_t i = 0; i < N; ++i) data_[i] = txt[i];
|
||||
}
|
||||
|
||||
template<std::input_iterator It, std::sentinel_for<It> S>
|
||||
requires std::convertible_to<std::iter_value_t<It>, CharT>
|
||||
constexpr explicit basic_fixed_string(It first, S last) noexcept
|
||||
constexpr basic_fixed_string(It begin, S end)
|
||||
{
|
||||
gsl_Expects(std::distance(first, last) == N);
|
||||
for (auto it = data_; first != last; ++first, ++it) *it = *first;
|
||||
MP_UNITS_EXPECTS(std::distance(begin, end) == N);
|
||||
for (auto it = data_; begin != end; ++begin, ++it) *it = *begin;
|
||||
}
|
||||
|
||||
template<std::convertible_to<CharT>... Rest>
|
||||
requires(1 + sizeof...(Rest) == N)
|
||||
constexpr explicit basic_fixed_string(CharT first, Rest... rest) noexcept : data_{first, rest..., CharT{}}
|
||||
template<std::ranges::input_range R>
|
||||
requires std::convertible_to<std::ranges::range_reference_t<R>, CharT>
|
||||
constexpr basic_fixed_string(std::from_range_t, R&& r)
|
||||
{
|
||||
MP_UNITS_EXPECTS(std::ranges::size(r) == N);
|
||||
for (auto it = data_; auto&& v : std::forward<R>(r)) *it++ = std::forward<decltype(v)>(v);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool empty() const noexcept { return N == 0; }
|
||||
[[nodiscard]] constexpr size_type size() const noexcept { return N; }
|
||||
[[nodiscard]] constexpr const_pointer data() const noexcept { return static_cast<const_pointer>(data_); }
|
||||
[[nodiscard]] constexpr const CharT* c_str() const noexcept { return data(); }
|
||||
[[nodiscard]] constexpr value_type operator[](size_type index) const noexcept
|
||||
{
|
||||
gsl_Expects(index < N);
|
||||
return data()[index];
|
||||
}
|
||||
constexpr basic_fixed_string(const basic_fixed_string&) noexcept = default;
|
||||
constexpr basic_fixed_string& operator=(const basic_fixed_string&) noexcept = default;
|
||||
|
||||
// iterator support
|
||||
[[nodiscard]] constexpr const_iterator begin() const noexcept { return data(); }
|
||||
[[nodiscard]] constexpr const_iterator cbegin() const noexcept { return data(); }
|
||||
[[nodiscard]] constexpr const_iterator end() const noexcept { return data() + size(); }
|
||||
[[nodiscard]] constexpr const_iterator cend() const noexcept { return data() + size(); }
|
||||
[[nodiscard]] constexpr const_iterator cbegin() const noexcept { return begin(); }
|
||||
[[nodiscard]] constexpr const_iterator cend() const noexcept { return end(); }
|
||||
[[nodiscard]] constexpr const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
|
||||
[[nodiscard]] constexpr const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
|
||||
[[nodiscard]] constexpr const_reverse_iterator crbegin() const noexcept { return rbegin(); }
|
||||
[[nodiscard]] constexpr const_reverse_iterator crend() const noexcept { return rend(); }
|
||||
|
||||
// capacity
|
||||
[[nodiscard]] static constexpr std::integral_constant<size_type, N> size() noexcept { return {}; }
|
||||
[[nodiscard]] static constexpr std::integral_constant<size_type, N> length() noexcept { return {}; }
|
||||
[[nodiscard]] static constexpr std::integral_constant<size_type, N> max_size() noexcept { return {}; }
|
||||
[[nodiscard]] static constexpr std::bool_constant<N == 0> empty() noexcept { return {}; }
|
||||
|
||||
// element access
|
||||
[[nodiscard]] constexpr const_reference operator[](size_type pos) const
|
||||
{
|
||||
MP_UNITS_EXPECTS(pos < N);
|
||||
return data()[pos];
|
||||
}
|
||||
|
||||
#if MP_UNITS_HOSTED
|
||||
[[nodiscard]] constexpr const_reference at(size_type pos) const
|
||||
{
|
||||
if (pos >= size()) throw std::out_of_range("basic_fixed_string::at");
|
||||
return (*this)[pos];
|
||||
}
|
||||
#endif
|
||||
|
||||
[[nodiscard]] constexpr const_reference front() const
|
||||
{
|
||||
MP_UNITS_EXPECTS(!empty());
|
||||
return (*this)[0];
|
||||
}
|
||||
[[nodiscard]] constexpr const_reference back() const
|
||||
{
|
||||
MP_UNITS_EXPECTS(!empty());
|
||||
return (*this)[N - 1];
|
||||
}
|
||||
|
||||
// modifiers
|
||||
constexpr void swap(basic_fixed_string& s) noexcept { swap_ranges(begin(), end(), s.begin()); }
|
||||
|
||||
// string operations
|
||||
[[nodiscard]] constexpr const_pointer c_str() const noexcept { return data(); }
|
||||
[[nodiscard]] constexpr const_pointer data() const noexcept { return static_cast<const_pointer>(data_); }
|
||||
[[nodiscard]] constexpr std::basic_string_view<CharT, Traits> view() const noexcept
|
||||
{
|
||||
return std::basic_string_view<CharT, Traits>(cbegin(), cend());
|
||||
}
|
||||
// NOLINTNEXTLINE(*-explicit-conversions, google-explicit-constructor)
|
||||
[[nodiscard]] constexpr explicit(false) operator std::basic_string_view<CharT>() const noexcept
|
||||
[[nodiscard]] constexpr explicit(false) operator std::basic_string_view<CharT, Traits>() const noexcept
|
||||
{
|
||||
return std::basic_string_view<CharT>(cbegin(), cend());
|
||||
return view();
|
||||
}
|
||||
|
||||
template<std::size_t N2>
|
||||
[[nodiscard]] constexpr friend basic_fixed_string<CharT, N + N2> operator+(
|
||||
const basic_fixed_string& lhs, const basic_fixed_string<CharT, N2>& rhs) noexcept
|
||||
[[nodiscard]] constexpr friend basic_fixed_string<CharT, N + N2, Traits> operator+(
|
||||
const basic_fixed_string& lhs, const basic_fixed_string<CharT, N2, Traits>& rhs) noexcept
|
||||
{
|
||||
CharT txt[N + N2 + 1] = {};
|
||||
|
||||
for (size_t i = 0; i != N; ++i) txt[i] = lhs[i];
|
||||
for (size_t i = 0; i != N2; ++i) txt[N + i] = rhs[i];
|
||||
|
||||
return basic_fixed_string<CharT, N + N2>(txt);
|
||||
CharT txt[N + N2];
|
||||
CharT* it = txt;
|
||||
for (CharT c : lhs) *it++ = c;
|
||||
for (CharT c : rhs) *it++ = c;
|
||||
return basic_fixed_string<CharT, N + N2, Traits>(txt, it);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool operator==(const basic_fixed_string&) const = default;
|
||||
|
||||
template<std::size_t N2>
|
||||
[[nodiscard]] friend constexpr bool operator==(const basic_fixed_string&, const basic_fixed_string<CharT, N2>&)
|
||||
[[nodiscard]] constexpr friend basic_fixed_string<CharT, N + 1, Traits> operator+(const basic_fixed_string& lhs,
|
||||
CharT rhs) noexcept
|
||||
{
|
||||
return false;
|
||||
CharT txt[N + 1];
|
||||
CharT* it = txt;
|
||||
for (CharT c : lhs) *it++ = c;
|
||||
*it++ = rhs;
|
||||
return basic_fixed_string<CharT, N + 1, Traits>(txt, it);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr friend basic_fixed_string<CharT, 1 + N, Traits> operator+(
|
||||
const CharT lhs, const basic_fixed_string& rhs) noexcept
|
||||
{
|
||||
CharT txt[1 + N];
|
||||
CharT* it = txt;
|
||||
*it++ = lhs;
|
||||
for (CharT c : rhs) *it++ = c;
|
||||
return basic_fixed_string<CharT, 1 + N, Traits>(txt, it);
|
||||
}
|
||||
|
||||
template<std::size_t N2>
|
||||
[[nodiscard]] consteval friend basic_fixed_string<CharT, N + N2 - 1, Traits> operator+(
|
||||
const basic_fixed_string& lhs, const CharT (&rhs)[N2]) noexcept
|
||||
{
|
||||
MP_UNITS_EXPECTS(rhs[N2 - 1] == CharT{});
|
||||
CharT txt[N + N2];
|
||||
CharT* it = txt;
|
||||
for (CharT c : lhs) *it++ = c;
|
||||
for (CharT c : rhs) *it++ = c;
|
||||
return txt;
|
||||
}
|
||||
|
||||
template<std::size_t N1>
|
||||
[[nodiscard]] consteval friend basic_fixed_string<CharT, N1 + N - 1, Traits> operator+(
|
||||
const CharT (&lhs)[N1], const basic_fixed_string& rhs) noexcept
|
||||
{
|
||||
MP_UNITS_EXPECTS(lhs[N1 - 1] == CharT{});
|
||||
CharT txt[N1 + N];
|
||||
CharT* it = txt;
|
||||
for (size_t i = 0; i != N1 - 1; ++i) *it++ = lhs[i];
|
||||
for (CharT c : rhs) *it++ = c;
|
||||
*it++ = CharT();
|
||||
return txt;
|
||||
}
|
||||
|
||||
// non-member comparison functions
|
||||
template<size_t N2>
|
||||
[[nodiscard]] friend constexpr bool operator==(const basic_fixed_string& lhs,
|
||||
const basic_fixed_string<CharT, N2, Traits>& rhs)
|
||||
{
|
||||
return lhs.view() == rhs.view();
|
||||
}
|
||||
template<size_t N2>
|
||||
[[nodiscard]] friend consteval bool operator==(const basic_fixed_string& lhs, const CharT (&rhs)[N2])
|
||||
{
|
||||
MP_UNITS_EXPECTS(rhs[N2 - 1] == CharT{});
|
||||
return lhs.view() == std::basic_string_view<CharT, Traits>(std::cbegin(rhs), std::cend(rhs) - 1);
|
||||
}
|
||||
|
||||
template<size_t N2>
|
||||
[[nodiscard]] friend constexpr auto operator<=>(const basic_fixed_string& lhs,
|
||||
const basic_fixed_string<CharT, N2>& rhs)
|
||||
const basic_fixed_string<CharT, N2, Traits>& rhs)
|
||||
{
|
||||
// TODO std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
|
||||
return detail::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
|
||||
return lhs.view() <=> rhs.view();
|
||||
}
|
||||
template<size_t N2>
|
||||
[[nodiscard]] friend consteval auto operator<=>(const basic_fixed_string& lhs, const CharT (&rhs)[N2])
|
||||
{
|
||||
MP_UNITS_EXPECTS(rhs[N2 - 1] == CharT{});
|
||||
return lhs.view() <=> std::basic_string_view<CharT, Traits>(std::cbegin(rhs), std::cend(rhs) - 1);
|
||||
}
|
||||
|
||||
template<typename Traits>
|
||||
// inserters and extractors
|
||||
#if MP_UNITS_HOSTED
|
||||
friend std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os,
|
||||
const basic_fixed_string<CharT, N>& str)
|
||||
const basic_fixed_string& str)
|
||||
{
|
||||
return os << str.c_str();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
// deduction guides
|
||||
template<one_of<char, char8_t, char16_t, char32_t, wchar_t> CharT, std::convertible_to<CharT>... Rest>
|
||||
basic_fixed_string(CharT, Rest...) -> basic_fixed_string<CharT, 1 + sizeof...(Rest)>;
|
||||
|
||||
template<typename CharT, std::size_t N>
|
||||
basic_fixed_string(const CharT (&str)[N]) -> basic_fixed_string<CharT, N - 1>;
|
||||
|
||||
template<typename CharT, std::convertible_to<CharT>... Rest>
|
||||
basic_fixed_string(CharT, Rest...) -> basic_fixed_string<CharT, 1 + sizeof...(Rest)>;
|
||||
template<one_of<char, char8_t, char16_t, char32_t, wchar_t> CharT, std::size_t N>
|
||||
basic_fixed_string(std::from_range_t, std::array<CharT, N>) -> basic_fixed_string<CharT, N>;
|
||||
|
||||
// typedef-names
|
||||
template<std::size_t N>
|
||||
using fixed_string = basic_fixed_string<char, N>;
|
||||
|
||||
template<std::size_t N>
|
||||
using fixed_u8string = basic_fixed_string<char8_t, N>;
|
||||
template<std::size_t N>
|
||||
using fixed_u16string = basic_fixed_string<char16_t, N>;
|
||||
template<std::size_t N>
|
||||
using fixed_u32string = basic_fixed_string<char32_t, N>;
|
||||
template<std::size_t N>
|
||||
using fixed_wstring = basic_fixed_string<wchar_t, N>;
|
||||
|
||||
template<std::size_t N>
|
||||
using fixed_u8string = basic_fixed_string<char8_t, N>;
|
||||
|
||||
template<std::size_t N>
|
||||
using fixed_u16string = basic_fixed_string<char16_t, N>;
|
||||
|
||||
template<std::size_t N>
|
||||
using fixed_u32string = basic_fixed_string<char32_t, N>;
|
||||
|
||||
} // namespace mp_units
|
||||
|
||||
// hash support
|
||||
template<std::size_t N>
|
||||
struct std::hash<mp_units::fixed_string<N>> : std::hash<std::string_view> {};
|
||||
template<std::size_t N>
|
||||
struct std::hash<mp_units::fixed_u8string<N>> : std::hash<std::u8string_view> {};
|
||||
template<std::size_t N>
|
||||
struct std::hash<mp_units::fixed_u16string<N>> : std::hash<std::u16string_view> {};
|
||||
template<std::size_t N>
|
||||
struct std::hash<mp_units::fixed_u32string<N>> : std::hash<std::u32string_view> {};
|
||||
template<std::size_t N>
|
||||
struct std::hash<mp_units::fixed_wstring<N>> : std::hash<std::wstring_view> {};
|
||||
|
||||
#if MP_UNITS_HOSTED
|
||||
// formatting support
|
||||
template<typename CharT, std::size_t N>
|
||||
struct MP_UNITS_STD_FMT::formatter<mp_units::basic_fixed_string<CharT, N>> : formatter<std::basic_string_view<CharT>> {
|
||||
template<typename FormatContext>
|
||||
@ -172,4 +300,6 @@ struct MP_UNITS_STD_FMT::formatter<mp_units::basic_fixed_string<CharT, N>> : for
|
||||
return formatter<std::basic_string_view<CharT>>::format(std::basic_string_view<CharT>(str), ctx);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
// NOLINTEND(*-avoid-c-arrays)
|
||||
|
@ -88,9 +88,8 @@ void to_base_specialization_of(const volatile Type<Params...>*);
|
||||
} // namespace detail
|
||||
|
||||
template<typename T, template<typename...> typename Type>
|
||||
// inline constexpr bool // TODO: Replace with concept when it works with MSVC
|
||||
concept is_derived_from_specialization_of = requires(T* t) { detail::to_base_specialization_of<Type>(t); };
|
||||
|
||||
inline constexpr bool is_derived_from_specialization_of =
|
||||
requires(T* t) { detail::to_base_specialization_of<Type>(t); };
|
||||
|
||||
namespace detail {
|
||||
|
||||
@ -137,7 +136,7 @@ concept one_of = (false || ... || std::same_as<T, Ts>);
|
||||
template<typename T, auto... Vs>
|
||||
[[nodiscard]] consteval bool contains()
|
||||
{
|
||||
return (false || ... || is_same_v<std::remove_const_t<decltype(Vs)>, T>);
|
||||
return (false || ... || is_same_v<MP_UNITS_REMOVE_CONST(decltype(Vs)), T>);
|
||||
}
|
||||
|
||||
template<template<typename...> typename T, typename... Ts>
|
||||
@ -161,7 +160,7 @@ template<typename T, std::same_as<T> auto V>
|
||||
template<typename T, auto V1, auto V2, auto... Vs>
|
||||
[[nodiscard]] consteval auto get()
|
||||
{
|
||||
if constexpr (is_same_v<T, std::remove_const_t<decltype(V1)>>)
|
||||
if constexpr (is_same_v<T, MP_UNITS_REMOVE_CONST(decltype(V1))>)
|
||||
return V1;
|
||||
else
|
||||
return get<T, V2, Vs...>();
|
||||
|
@ -24,22 +24,21 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mp-units/bits/requires_hosted.h>
|
||||
//
|
||||
#include <mp-units/bits/fmt.h>
|
||||
#include <mp-units/bits/module_macros.h>
|
||||
#include <mp-units/compat_macros.h>
|
||||
#include <mp-units/ext/algorithm.h>
|
||||
#include <mp-units/framework/customization_points.h>
|
||||
#include <mp-units/framework/quantity.h>
|
||||
#include <mp-units/framework/unit.h>
|
||||
|
||||
namespace mp_units::detail {
|
||||
#ifndef MP_UNITS_IN_MODULE_INTERFACE
|
||||
#include <locale>
|
||||
#endif
|
||||
|
||||
template<typename Char>
|
||||
struct fill_align_width_format_specs {
|
||||
fill_t<Char> fill;
|
||||
fmt_align align : 4 = fmt_align::none;
|
||||
int width = 0;
|
||||
fmt_arg_ref<Char> width_ref;
|
||||
};
|
||||
namespace mp_units::detail {
|
||||
|
||||
template<typename Char>
|
||||
[[nodiscard]] constexpr const Char* at_most_one_of(const Char* begin, const Char* end, std::string_view modifiers)
|
||||
@ -51,6 +50,17 @@ template<typename Char>
|
||||
return it;
|
||||
}
|
||||
|
||||
// TODO the below should be exposed by the C++ Standard Library (used in our examples)
|
||||
MP_UNITS_EXPORT_BEGIN
|
||||
|
||||
template<typename Char>
|
||||
struct fill_align_width_format_specs {
|
||||
fill_t<Char> fill;
|
||||
fmt_align align : 4 = fmt_align::none;
|
||||
int width = 0;
|
||||
fmt_arg_ref<Char> width_ref;
|
||||
};
|
||||
|
||||
template<typename Char, typename Specs>
|
||||
[[nodiscard]] constexpr const Char* parse_fill_align_width(MP_UNITS_STD_FMT::basic_format_parse_context<Char>& ctx,
|
||||
const Char* begin, const Char* end, Specs& specs,
|
||||
@ -89,6 +99,8 @@ OutputIt format_global_buffer(OutputIt out, const fill_align_width_format_specs<
|
||||
return MP_UNITS_STD_FMT::format_to(out, "}}");
|
||||
}
|
||||
|
||||
MP_UNITS_EXPORT_END
|
||||
|
||||
} // namespace mp_units::detail
|
||||
|
||||
//
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <mp-units/bits/hacks.h>
|
||||
#include <mp-units/bits/module_macros.h>
|
||||
#include <mp-units/bits/text_tools.h>
|
||||
#include <mp-units/compat_macros.h>
|
||||
#include <mp-units/ext/fixed_string.h>
|
||||
#include <mp-units/ext/type_traits.h>
|
||||
#include <mp-units/framework/dimension_concepts.h>
|
||||
@ -33,12 +34,13 @@
|
||||
#include <mp-units/framework/symbol_text.h>
|
||||
|
||||
#ifndef MP_UNITS_IN_MODULE_INTERFACE
|
||||
#include <gsl/gsl-lite.hpp>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#if MP_UNITS_HOSTED
|
||||
#include <string>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace mp_units {
|
||||
@ -280,7 +282,8 @@ template<typename CharT, std::output_iterator<CharT> Out, typename... Expr>
|
||||
constexpr Out dimension_symbol_impl(Out out, const derived_dimension<Expr...>&, const dimension_symbol_formatting& fmt,
|
||||
bool negative_power)
|
||||
{
|
||||
gsl_Expects(negative_power == false);
|
||||
(void)negative_power;
|
||||
MP_UNITS_EXPECTS(negative_power == false);
|
||||
return dimension_symbol_impl<CharT>(out, typename derived_dimension<Expr...>::_num_{},
|
||||
typename derived_dimension<Expr...>::_den_{}, fmt);
|
||||
}
|
||||
@ -317,9 +320,15 @@ MP_UNITS_EXPORT template<dimension_symbol_formatting fmt = dimension_symbol_form
|
||||
#endif
|
||||
{
|
||||
auto get_size = []() consteval {
|
||||
#if MP_UNITS_HOSTED
|
||||
std::basic_string<CharT> buffer;
|
||||
dimension_symbol_to<CharT>(std::back_inserter(buffer), D{}, fmt);
|
||||
return buffer.size();
|
||||
#else
|
||||
std::array<CharT, 128> buffer; // TODO unsafe
|
||||
auto end = dimension_symbol_to<CharT>(buffer.begin(), D{}, fmt);
|
||||
return end - buffer.begin();
|
||||
#endif
|
||||
};
|
||||
|
||||
#if MP_UNITS_API_STRING_VIEW_RET // Permitting static constexpr variables in constexpr functions
|
||||
@ -328,8 +337,7 @@ MP_UNITS_EXPORT template<dimension_symbol_formatting fmt = dimension_symbol_form
|
||||
return std::string_view(buffer.data(), size);
|
||||
#else
|
||||
constexpr std::size_t size = get_size();
|
||||
constexpr auto buffer = detail::get_symbol_buffer<CharT, size, fmt>(D{});
|
||||
return basic_fixed_string<CharT, size>(buffer.begin(), buffer.end());
|
||||
return basic_fixed_string(std::from_range, detail::get_symbol_buffer<CharT, size, fmt>(D{}));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -109,6 +109,6 @@ concept Dimension = detail::BaseDimension<T> || detail::DerivedDimension<T>;
|
||||
* Satisfied when both argument satisfy a `Dimension` concept and when they compare equal.
|
||||
*/
|
||||
MP_UNITS_EXPORT template<typename T, auto D>
|
||||
concept DimensionOf = Dimension<T> && Dimension<std::remove_const_t<decltype(D)>> && (T{} == D);
|
||||
concept DimensionOf = Dimension<T> && Dimension<MP_UNITS_REMOVE_CONST(decltype(D))> && (T{} == D);
|
||||
|
||||
} // namespace mp_units
|
||||
|
@ -534,8 +534,8 @@ template<template<typename> typename Proj, template<typename...> typename To, ty
|
||||
expr_type_projectable<Proj>... Dens>
|
||||
[[nodiscard]] consteval auto expr_map_impl(type_list<Nums...>, type_list<Dens...>)
|
||||
{
|
||||
return (OneType{} * ... * map_power(typename expr_type_map<std::remove_const_t<Nums>, Proj>::type{})) /
|
||||
(OneType{} * ... * map_power(typename expr_type_map<std::remove_const_t<Dens>, Proj>::type{}));
|
||||
return (OneType{} * ... * map_power(typename expr_type_map<Nums, Proj>::type{})) /
|
||||
(OneType{} * ... * map_power(typename expr_type_map<Dens, Proj>::type{}));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -38,6 +38,7 @@
|
||||
#ifndef MP_UNITS_IN_MODULE_INTERFACE
|
||||
#include <concepts>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <numbers>
|
||||
#include <optional>
|
||||
#endif
|
||||
@ -278,7 +279,7 @@ template<typename T>
|
||||
// As this function should only be called at compile time, the terminations herein function as
|
||||
// "parameter-compatible static_asserts", and should not result in terminations at runtime.
|
||||
if (exp < 0) {
|
||||
std::terminate(); // int_power only supports positive integer powers
|
||||
std::abort(); // int_power only supports positive integer powers
|
||||
}
|
||||
|
||||
constexpr auto checked_multiply = [](auto a, auto b) {
|
||||
@ -286,7 +287,7 @@ template<typename T>
|
||||
MP_UNITS_DIAGNOSTIC_PUSH
|
||||
MP_UNITS_DIAGNOSTIC_IGNORE_FLOAT_EQUAL
|
||||
if (result / a != b) {
|
||||
std::terminate(); // Wraparound detected
|
||||
std::abort(); // Wraparound detected
|
||||
}
|
||||
MP_UNITS_DIAGNOSTIC_POP
|
||||
return result;
|
||||
@ -294,17 +295,8 @@ template<typename T>
|
||||
|
||||
constexpr auto checked_square = [checked_multiply](auto a) { return checked_multiply(a, a); };
|
||||
|
||||
// TODO(chogg): Unify this implementation with the one in pow.h. That one takes its exponent as a
|
||||
// template parameter, rather than a function parameter.
|
||||
|
||||
if (exp == 0) {
|
||||
return T{1};
|
||||
}
|
||||
|
||||
if (exp % 2 == 1) {
|
||||
return checked_multiply(base, int_power(base, exp - 1));
|
||||
}
|
||||
|
||||
if (exp == 0) return T{1};
|
||||
if (exp % 2 == 1) return checked_multiply(base, int_power(base, exp - 1));
|
||||
return checked_square(int_power(base, exp / 2));
|
||||
}
|
||||
|
||||
@ -319,12 +311,12 @@ template<typename T>
|
||||
// terminations is to act as "static_assert substitutes", not to actually terminate at runtime.
|
||||
const auto exp = get_exponent(el);
|
||||
if (exp.den != 1) {
|
||||
std::terminate(); // Rational powers not yet supported
|
||||
std::abort(); // Rational powers not yet supported
|
||||
}
|
||||
|
||||
if (exp.num < 0) {
|
||||
if constexpr (std::is_integral_v<T>) {
|
||||
std::terminate(); // Cannot represent reciprocal as integer
|
||||
std::abort(); // Cannot represent reciprocal as integer
|
||||
} else {
|
||||
return T{1} / compute_base_power<T>(inverse(el));
|
||||
}
|
||||
@ -339,7 +331,6 @@ template<typename T>
|
||||
// The input is the desired result, but in a (wider) intermediate type. The point of this function
|
||||
// is to cast to the desired type, but avoid overflow in doing so.
|
||||
template<typename To, typename From>
|
||||
// TODO(chogg): Migrate this to use `treat_as_floating_point`.
|
||||
requires(!std::is_integral_v<To> || std::is_integral_v<From>)
|
||||
[[nodiscard]] consteval To checked_static_cast(From x)
|
||||
{
|
||||
@ -347,7 +338,7 @@ template<typename To, typename From>
|
||||
// to produce compiler errors, because we cannot `static_assert` on function arguments.
|
||||
if constexpr (std::is_integral_v<To>) {
|
||||
if (!std::in_range<To>(x)) {
|
||||
std::terminate(); // Cannot represent magnitude in this type
|
||||
std::abort(); // Cannot represent magnitude in this type
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
// IWYU pragma: private, include <mp-units/framework.h>
|
||||
#include <mp-units/bits/module_macros.h>
|
||||
#include <mp-units/bits/sudo_cast.h>
|
||||
#include <mp-units/compat_macros.h>
|
||||
#include <mp-units/framework/customization_points.h>
|
||||
#include <mp-units/framework/dimension_concepts.h>
|
||||
#include <mp-units/framework/quantity_concepts.h>
|
||||
@ -36,7 +37,6 @@
|
||||
#include <mp-units/framework/unit_concepts.h>
|
||||
|
||||
#ifndef MP_UNITS_IN_MODULE_INTERFACE
|
||||
#include <gsl/gsl-lite.hpp>
|
||||
#include <compare> // IWYU pragma: export
|
||||
#include <utility>
|
||||
#endif
|
||||
@ -140,8 +140,7 @@ public:
|
||||
|
||||
template<typename Value>
|
||||
requires std::same_as<std::remove_cvref_t<Value>, Rep>
|
||||
constexpr quantity(Value&& v, std::remove_const_t<decltype(R)>) :
|
||||
numerical_value_is_an_implementation_detail_(std::forward<Value>(v))
|
||||
constexpr quantity(Value&& v, decltype(R)) : numerical_value_is_an_implementation_detail_(std::forward<Value>(v))
|
||||
{
|
||||
}
|
||||
|
||||
@ -353,7 +352,7 @@ public:
|
||||
friend constexpr decltype(auto) operator%=(Q&& lhs, const quantity& rhs)
|
||||
|
||||
{
|
||||
gsl_ExpectsDebug(rhs != zero());
|
||||
MP_UNITS_EXPECTS_DEBUG(rhs != zero());
|
||||
lhs.numerical_value_is_an_implementation_detail_ %= rhs.numerical_value_is_an_implementation_detail_;
|
||||
return std::forward<Q>(lhs);
|
||||
}
|
||||
@ -393,7 +392,7 @@ public:
|
||||
}
|
||||
friend constexpr decltype(auto) operator/=(Q&& lhs, const Value& v)
|
||||
{
|
||||
gsl_ExpectsDebug(v != quantity_values<Value>::zero());
|
||||
MP_UNITS_EXPECTS_DEBUG(v != quantity_values<Value>::zero());
|
||||
lhs.numerical_value_is_an_implementation_detail_ /= v;
|
||||
return std::forward<Q>(lhs);
|
||||
}
|
||||
@ -407,7 +406,7 @@ public:
|
||||
}
|
||||
friend constexpr decltype(auto) operator/=(Q1&& lhs, const Q2& rhs)
|
||||
{
|
||||
gsl_ExpectsDebug(rhs != rhs.zero());
|
||||
MP_UNITS_EXPECTS_DEBUG(rhs != rhs.zero());
|
||||
lhs.numerical_value_is_an_implementation_detail_ /= rhs.numerical_value_is_an_implementation_detail_;
|
||||
return std::forward<Q1>(lhs);
|
||||
}
|
||||
@ -451,7 +450,7 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
|
||||
detail::CommonlyInvocableQuantities<std::modulus<>, quantity<R1, Rep1>, quantity<R2, Rep2>>
|
||||
[[nodiscard]] constexpr Quantity auto operator%(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs)
|
||||
{
|
||||
gsl_ExpectsDebug(rhs != rhs.zero());
|
||||
MP_UNITS_EXPECTS_DEBUG(rhs != rhs.zero());
|
||||
using ret = detail::common_quantity_for<std::modulus<>, quantity<R1, Rep1>, quantity<R2, Rep2>>;
|
||||
const ret ret_lhs(lhs);
|
||||
const ret ret_rhs(rhs);
|
||||
@ -486,7 +485,7 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
|
||||
requires detail::InvocableQuantities<std::divides<>, quantity<R1, Rep1>, quantity<R2, Rep2>>
|
||||
[[nodiscard]] constexpr Quantity auto operator/(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs)
|
||||
{
|
||||
gsl_ExpectsDebug(rhs != rhs.zero());
|
||||
MP_UNITS_EXPECTS_DEBUG(rhs != rhs.zero());
|
||||
return quantity{lhs.numerical_value_ref_in(get_unit(R1)) / rhs.numerical_value_ref_in(get_unit(R2)), R1 / R2};
|
||||
}
|
||||
|
||||
@ -495,7 +494,7 @@ template<auto R, typename Rep, typename Value>
|
||||
detail::InvokeResultOf<get_quantity_spec(R).character, std::divides<>, Rep, const Value&>
|
||||
[[nodiscard]] constexpr QuantityOf<get_quantity_spec(R)> auto operator/(const quantity<R, Rep>& q, const Value& v)
|
||||
{
|
||||
gsl_ExpectsDebug(v != quantity_values<Value>::zero());
|
||||
MP_UNITS_EXPECTS_DEBUG(v != quantity_values<Value>::zero());
|
||||
return quantity{q.numerical_value_ref_in(get_unit(R)) / v, R};
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ void to_base_specialization_of_quantity(const volatile quantity<R, Rep>*);
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_derived_from_specialization_of_quantity =
|
||||
requires(std::remove_reference_t<T>* t) { to_base_specialization_of_quantity(t); };
|
||||
requires(T* t) { to_base_specialization_of_quantity(t); };
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
@ -169,8 +169,7 @@ public:
|
||||
|
||||
template<typename Q>
|
||||
requires QuantityOf<std::remove_cvref_t<Q>, get_quantity_spec(R)> && std::constructible_from<quantity_type, Q>
|
||||
constexpr quantity_point(Q&& q, std::remove_const_t<decltype(PO)>) :
|
||||
quantity_from_origin_is_an_implementation_detail_(std::forward<Q>(q))
|
||||
constexpr quantity_point(Q&& q, decltype(PO)) : quantity_from_origin_is_an_implementation_detail_(std::forward<Q>(q))
|
||||
{
|
||||
}
|
||||
|
||||
@ -187,7 +186,6 @@ public:
|
||||
|
||||
template<QuantityPointOf<absolute_point_origin> QP>
|
||||
requires std::constructible_from<quantity_type, typename QP::quantity_type>
|
||||
// TODO add perfect forwarding
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
constexpr explicit(!std::convertible_to<typename QP::quantity_type, quantity_type>) quantity_point(const QP& qp) :
|
||||
quantity_from_origin_is_an_implementation_detail_([&] {
|
||||
@ -222,7 +220,7 @@ public:
|
||||
[[nodiscard]] constexpr MP_UNITS_CONSTRAINED_AUTO_WORKAROUND(QuantityPointOf<NewPO{}>) auto point_for(
|
||||
NewPO new_origin) const
|
||||
{
|
||||
if constexpr (is_same_v<NewPO, std::remove_const_t<decltype(point_origin)>>)
|
||||
if constexpr (is_same_v<NewPO, decltype(PO)>)
|
||||
return *this;
|
||||
else
|
||||
return ::mp_units::quantity_point{*this - new_origin, new_origin};
|
||||
@ -388,7 +386,7 @@ explicit(
|
||||
|
||||
template<auto R1, auto PO1, typename Rep1, auto R2, typename Rep2>
|
||||
// TODO simplify when gcc catches up
|
||||
requires ReferenceOf<std::remove_const_t<decltype(R2)>, PO1.quantity_spec>
|
||||
requires ReferenceOf<MP_UNITS_REMOVE_CONST(decltype(R2)), PO1.quantity_spec>
|
||||
[[nodiscard]] constexpr QuantityPoint auto operator+(const quantity_point<R1, PO1, Rep1>& qp,
|
||||
const quantity<R2, Rep2>& q)
|
||||
requires requires { qp.quantity_ref_from(PO1) + q; }
|
||||
@ -401,7 +399,7 @@ template<auto R1, auto PO1, typename Rep1, auto R2, typename Rep2>
|
||||
|
||||
template<auto R1, typename Rep1, auto R2, auto PO2, typename Rep2>
|
||||
// TODO simplify when gcc catches up
|
||||
requires ReferenceOf<std::remove_const_t<decltype(R1)>, PO2.quantity_spec>
|
||||
requires ReferenceOf<MP_UNITS_REMOVE_CONST(decltype(R1)), PO2.quantity_spec>
|
||||
[[nodiscard]] constexpr QuantityPoint auto operator+(const quantity<R1, Rep1>& q,
|
||||
const quantity_point<R2, PO2, Rep2>& qp)
|
||||
requires requires { q + qp.quantity_ref_from(PO2); }
|
||||
@ -425,7 +423,7 @@ template<Quantity Q, PointOrigin PO>
|
||||
|
||||
template<auto R1, auto PO1, typename Rep1, auto R2, typename Rep2>
|
||||
// TODO simplify when gcc catches up
|
||||
requires ReferenceOf<std::remove_const_t<decltype(R2)>, PO1.quantity_spec>
|
||||
requires ReferenceOf<MP_UNITS_REMOVE_CONST(decltype(R2)), PO1.quantity_spec>
|
||||
[[nodiscard]] constexpr QuantityPoint auto operator-(const quantity_point<R1, PO1, Rep1>& qp,
|
||||
const quantity<R2, Rep2>& q)
|
||||
requires requires { qp.quantity_ref_from(PO1) - q; }
|
||||
|
@ -105,7 +105,7 @@ concept PointOrigin = detail::AbsolutePointOrigin<T> || detail::RelativePointOri
|
||||
* Satisfied by all quantity point origins that are defined using a provided quantity specification.
|
||||
*/
|
||||
MP_UNITS_EXPORT template<typename T, auto QS>
|
||||
concept PointOriginFor = PointOrigin<T> && QuantitySpecOf<std::remove_const_t<decltype(QS)>, T::quantity_spec>;
|
||||
concept PointOriginFor = PointOrigin<T> && QuantitySpecOf<MP_UNITS_REMOVE_CONST(decltype(QS)), T::quantity_spec>;
|
||||
|
||||
MP_UNITS_EXPORT template<Reference auto R, PointOriginFor<get_quantity_spec(R)> auto PO,
|
||||
RepresentationOf<get_quantity_spec(R).character> Rep>
|
||||
@ -141,7 +141,7 @@ template<PointOrigin PO1, PointOrigin PO2>
|
||||
|
||||
template<typename T, auto V>
|
||||
concept SameAbsolutePointOriginAs =
|
||||
PointOrigin<T> && PointOrigin<std::remove_const_t<decltype(V)>> && same_absolute_point_origins(T{}, V);
|
||||
PointOrigin<T> && PointOrigin<MP_UNITS_REMOVE_CONST(decltype(V))> && same_absolute_point_origins(T{}, V);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
@ -38,8 +38,10 @@
|
||||
#include <mp-units/framework/representation_concepts.h>
|
||||
|
||||
#ifndef MP_UNITS_IN_MODULE_INTERFACE
|
||||
#include <concepts>
|
||||
#include <cstdint>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#endif
|
||||
|
||||
namespace mp_units {
|
||||
@ -216,11 +218,11 @@ MP_UNITS_EXPORT_END
|
||||
*/
|
||||
#ifdef MP_UNITS_API_NO_CRTP
|
||||
template<detail::BaseDimension auto Dim, one_of<quantity_character> auto... Args>
|
||||
requires(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>)
|
||||
requires(... && !QuantitySpec<decltype(Args)>)
|
||||
struct quantity_spec<Dim, Args...> : detail::quantity_spec_interface {
|
||||
#else
|
||||
template<typename Self, detail::BaseDimension auto Dim, one_of<quantity_character> auto... Args>
|
||||
requires(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>)
|
||||
requires(... && !QuantitySpec<decltype(Args)>)
|
||||
struct quantity_spec<Self, Dim, Args...> : detail::quantity_spec_interface<Self> {
|
||||
#endif
|
||||
static constexpr detail::BaseDimension auto dimension = Dim;
|
||||
@ -259,11 +261,11 @@ struct quantity_spec<Self, Dim, Args...> : detail::quantity_spec_interface<Self>
|
||||
*/
|
||||
#ifdef MP_UNITS_API_NO_CRTP
|
||||
template<detail::IntermediateDerivedQuantitySpec auto Eq, one_of<quantity_character> auto... Args>
|
||||
requires(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>)
|
||||
requires(... && !QuantitySpec<decltype(Args)>)
|
||||
struct quantity_spec<Eq, Args...> : detail::quantity_spec_interface {
|
||||
#else
|
||||
template<typename Self, detail::IntermediateDerivedQuantitySpec auto Eq, one_of<quantity_character> auto... Args>
|
||||
requires(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>)
|
||||
requires(... && !QuantitySpec<decltype(Args)>)
|
||||
struct quantity_spec<Self, Eq, Args...> : detail::quantity_spec_interface<Self> {
|
||||
#endif
|
||||
static constexpr auto _equation_ = Eq;
|
||||
@ -300,12 +302,12 @@ struct quantity_spec<Self, Eq, Args...> : detail::quantity_spec_interface<Self>
|
||||
*/
|
||||
#ifdef MP_UNITS_API_NO_CRTP
|
||||
template<detail::NamedQuantitySpec auto QS, one_of<quantity_character, struct is_kind> auto... Args>
|
||||
requires(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>)
|
||||
struct quantity_spec<QS, Args...> : std::remove_const_t<decltype(QS)> {
|
||||
requires(... && !QuantitySpec<decltype(Args)>)
|
||||
struct quantity_spec<QS, Args...> : decltype(QS) {
|
||||
#else
|
||||
template<typename Self, detail::NamedQuantitySpec auto QS, one_of<quantity_character, struct is_kind> auto... Args>
|
||||
requires(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>)
|
||||
struct quantity_spec<Self, QS, Args...> : std::remove_const_t<decltype(QS)> {
|
||||
requires(... && !QuantitySpec<decltype(Args)>)
|
||||
struct quantity_spec<Self, QS, Args...> : decltype(QS) {
|
||||
#endif
|
||||
static constexpr auto _parent_ = QS;
|
||||
static constexpr quantity_character character = detail::quantity_character_init<Args...>(QS.character);
|
||||
@ -359,16 +361,16 @@ struct quantity_spec<Self, QS, Args...> : std::remove_const_t<decltype(QS)> {
|
||||
#ifdef MP_UNITS_API_NO_CRTP
|
||||
template<detail::NamedQuantitySpec auto QS, detail::IntermediateDerivedQuantitySpec auto Eq,
|
||||
one_of<quantity_character, struct is_kind> auto... Args>
|
||||
requires(!requires { QS._equation_; } ||
|
||||
(requires { QS._equation_; } && (explicitly_convertible(Eq, QS._equation_)))) &&
|
||||
(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>)
|
||||
requires(!requires { QS._equation_; } || (requires {
|
||||
QS._equation_;
|
||||
} && (explicitly_convertible(Eq, QS._equation_)))) && (... && !QuantitySpec<decltype(Args)>)
|
||||
struct quantity_spec<QS, Eq, Args...> : quantity_spec<QS, Args...> {
|
||||
#else
|
||||
template<typename Self, detail::NamedQuantitySpec auto QS, detail::IntermediateDerivedQuantitySpec auto Eq,
|
||||
one_of<quantity_character, struct is_kind> auto... Args>
|
||||
requires(!requires { QS._equation_; } ||
|
||||
(requires { QS._equation_; } && (explicitly_convertible(Eq, QS._equation_)))) &&
|
||||
(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>)
|
||||
requires(!requires { QS._equation_; } || (requires {
|
||||
QS._equation_;
|
||||
} && (explicitly_convertible(Eq, QS._equation_)))) && (... && !QuantitySpec<decltype(Args)>)
|
||||
struct quantity_spec<Self, QS, Eq, Args...> : quantity_spec<Self, QS, Args...> {
|
||||
#endif
|
||||
static constexpr auto _equation_ = Eq;
|
||||
@ -481,7 +483,7 @@ struct kind_of_<Q> : quantity_spec<kind_of_<Q>, Q{}> {
|
||||
|
||||
MP_UNITS_EXPORT template<detail::QuantitySpecWithNoSpecifiers auto Q>
|
||||
requires(detail::get_kind_tree_root(Q) == Q)
|
||||
inline constexpr kind_of_<std::remove_const_t<decltype(Q)>> kind_of;
|
||||
inline constexpr kind_of_<MP_UNITS_REMOVE_CONST(decltype(Q))> kind_of;
|
||||
|
||||
namespace detail {
|
||||
|
||||
@ -491,7 +493,7 @@ struct is_dimensionless<struct dimensionless> : std::true_type {};
|
||||
template<QuantitySpec auto... From, QuantitySpec Q>
|
||||
[[nodiscard]] consteval QuantitySpec auto clone_kind_of(Q q)
|
||||
{
|
||||
if constexpr ((... && QuantityKindSpec<std::remove_const_t<decltype(From)>>))
|
||||
if constexpr ((... && QuantityKindSpec<MP_UNITS_REMOVE_CONST(decltype(From))>))
|
||||
return kind_of<Q{}>;
|
||||
else
|
||||
return q;
|
||||
@ -550,11 +552,6 @@ template<std::intmax_t Num, std::intmax_t Den = 1, QuantitySpec Q>
|
||||
requires detail::non_zero<Den>
|
||||
[[nodiscard]] consteval QuantitySpec auto pow(Q q)
|
||||
{
|
||||
// TODO Does the below make sense?
|
||||
// `2 * 2` should compare to `4`
|
||||
// `2 * one * (2 * one)` should compare to `4 * one`
|
||||
// `2 * rad * (2 * rad)` should compare to `4 * rad^2`
|
||||
// all are dimensionless quantities :-(
|
||||
if constexpr (Num == 0 || Q{} == dimensionless)
|
||||
return dimensionless;
|
||||
else if constexpr (detail::ratio{Num, Den} == 1)
|
||||
@ -564,11 +561,9 @@ template<std::intmax_t Num, std::intmax_t Den = 1, QuantitySpec Q>
|
||||
detail::expr_pow<Num, Den, derived_quantity_spec, struct dimensionless, detail::type_list_of_quantity_spec_less>(
|
||||
detail::remove_kind(q)));
|
||||
else if constexpr (Den == 1)
|
||||
return detail::clone_kind_of<Q{}>(
|
||||
derived_quantity_spec<power<std::remove_const_t<decltype(detail::remove_kind(Q{}))>, Num>>{});
|
||||
return detail::clone_kind_of<Q{}>(derived_quantity_spec<power<decltype(detail::remove_kind(Q{})), Num>>{});
|
||||
else
|
||||
return detail::clone_kind_of<Q{}>(
|
||||
derived_quantity_spec<power<std::remove_const_t<decltype(detail::remove_kind(Q{}))>, Num, Den>>{});
|
||||
return detail::clone_kind_of<Q{}>(derived_quantity_spec<power<decltype(detail::remove_kind(Q{})), Num, Den>>{});
|
||||
}
|
||||
|
||||
|
||||
@ -915,12 +910,11 @@ template<typename From, typename To>
|
||||
return extract_results{false};
|
||||
else if constexpr (from_exp > to_exp)
|
||||
return extract_results{true, pow<to_exp.num, to_exp.den>(from_factor), pow<to_exp.num, to_exp.den>(to_factor),
|
||||
prepend_rest::first,
|
||||
power_or_T<std::remove_cvref_t<decltype(from_factor)>, from_exp - to_exp>{}};
|
||||
prepend_rest::first, power_or_T<decltype(from_factor), from_exp - to_exp>{}};
|
||||
else
|
||||
return extract_results{true, pow<from_exp.num, from_exp.den>(from_factor),
|
||||
pow<from_exp.num, from_exp.den>(to_factor), prepend_rest::second,
|
||||
power_or_T<std::remove_cvref_t<decltype(to_factor)>, to_exp - from_exp>{}};
|
||||
power_or_T<decltype(to_factor), to_exp - from_exp>{}};
|
||||
}
|
||||
}
|
||||
|
||||
@ -934,7 +928,7 @@ template<process_entities Entities, auto Ext, TypeList NumFrom, TypeList DenFrom
|
||||
if constexpr (Ext.prepend == prepend_rest::no)
|
||||
return min(res, are_ingredients_convertible(num_from, den_from, num_to, den_to));
|
||||
else {
|
||||
using elem = std::remove_cvref_t<decltype(Ext.elem)>;
|
||||
using elem = decltype(Ext.elem);
|
||||
if constexpr (Entities == process_entities::numerators) {
|
||||
if constexpr (Ext.prepend == prepend_rest::first)
|
||||
return min(res, are_ingredients_convertible(type_list_push_front<NumFrom, elem>{}, den_from, num_to, den_to));
|
||||
@ -959,7 +953,7 @@ template<process_entities Entities, auto Ext, TypeList NumFrom, TypeList DenFrom
|
||||
if constexpr (Ext.prepend == prepend_rest::no)
|
||||
return are_ingredients_convertible(num_from, den_from, num_to, den_to);
|
||||
else {
|
||||
using elem = std::remove_cvref_t<decltype(Ext.elem)>;
|
||||
using elem = decltype(Ext.elem);
|
||||
if constexpr (Entities == process_entities::from) {
|
||||
if constexpr (Ext.prepend == prepend_rest::first)
|
||||
return are_ingredients_convertible(type_list_push_front<NumFrom, elem>{}, den_from, num_to, den_to);
|
||||
@ -1342,8 +1336,7 @@ template<QuantitySpec From, QuantitySpec To>
|
||||
using enum specs_convertible_result;
|
||||
return res == no ? no : yes;
|
||||
};
|
||||
if constexpr ((NamedQuantitySpec<std::remove_cvref_t<decltype(from_kind)>> &&
|
||||
NamedQuantitySpec<std::remove_cvref_t<decltype(to_kind)>>) ||
|
||||
if constexpr ((NamedQuantitySpec<decltype(from_kind)> && NamedQuantitySpec<decltype(to_kind)>) ||
|
||||
get_complexity(from_kind) == get_complexity(to_kind))
|
||||
return convertible_impl(from_kind, to_kind);
|
||||
else if constexpr (get_complexity(from_kind) > get_complexity(to_kind))
|
||||
@ -1396,7 +1389,7 @@ template<QuantitySpec From, QuantitySpec To>
|
||||
return are_ingredients_convertible(from, to);
|
||||
} else if constexpr (IntermediateDerivedQuantitySpec<From>) {
|
||||
auto res = explode<get_complexity(to)>(from);
|
||||
if constexpr (NamedQuantitySpec<std::remove_const_t<decltype(res.quantity)>>)
|
||||
if constexpr (NamedQuantitySpec<decltype(res.quantity)>)
|
||||
return convertible_impl(res.quantity, to);
|
||||
else if constexpr (requires { to._equation_; }) {
|
||||
auto eq = explode_to_equation(to);
|
||||
@ -1405,7 +1398,7 @@ template<QuantitySpec From, QuantitySpec To>
|
||||
return are_ingredients_convertible(from, to);
|
||||
} else if constexpr (IntermediateDerivedQuantitySpec<To>) {
|
||||
auto res = explode<get_complexity(from)>(to);
|
||||
if constexpr (NamedQuantitySpec<std::remove_const_t<decltype(res.quantity)>>)
|
||||
if constexpr (NamedQuantitySpec<decltype(res.quantity)>)
|
||||
return min(res.result, convertible_impl(from, res.quantity));
|
||||
else if constexpr (requires { from._equation_; })
|
||||
return min(res.result, convertible_impl(from._equation_, res.quantity));
|
||||
@ -1450,7 +1443,7 @@ namespace detail {
|
||||
|
||||
template<QuantitySpec Q>
|
||||
requires requires(Q q) { get_kind_tree_root(q); }
|
||||
using to_kind = std::remove_const_t<decltype(get_kind_tree_root(Q{}))>;
|
||||
using to_kind = decltype(get_kind_tree_root(Q{}));
|
||||
|
||||
#ifdef MP_UNITS_API_NO_CRTP
|
||||
template<NamedQuantitySpec auto QS, auto... Args>
|
||||
@ -1507,8 +1500,8 @@ template<QuantitySpec Q1, QuantitySpec Q2>
|
||||
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(detail::remove_kind(q1))>;
|
||||
using QQ2 = std::remove_const_t<decltype(detail::remove_kind(q2))>;
|
||||
using QQ1 = decltype(detail::remove_kind(q1));
|
||||
using QQ2 = decltype(detail::remove_kind(q2));
|
||||
|
||||
// NOLINTBEGIN(bugprone-branch-clone)
|
||||
if constexpr (is_same_v<Q1, Q2>)
|
||||
|
@ -140,15 +140,14 @@ namespace detail {
|
||||
|
||||
template<auto To, auto From>
|
||||
concept NestedQuantityKindSpecOf =
|
||||
QuantitySpec<std::remove_const_t<decltype(From)>> && QuantitySpec<std::remove_const_t<decltype(To)>> &&
|
||||
get_kind(From) != get_kind(To) &&
|
||||
std::derived_from<std::remove_cvref_t<decltype(To)>, std::remove_cvref_t<decltype(get_kind(From)._quantity_spec_)>>;
|
||||
QuantitySpec<decltype(From)> && QuantitySpec<decltype(To)> && get_kind(From) != get_kind(To) &&
|
||||
std::derived_from<decltype(To), std::remove_const_t<decltype(get_kind(From)._quantity_spec_)>>;
|
||||
|
||||
}
|
||||
|
||||
MP_UNITS_EXPORT template<typename T, auto QS>
|
||||
concept QuantitySpecOf =
|
||||
QuantitySpec<T> && QuantitySpec<std::remove_const_t<decltype(QS)>> && implicitly_convertible(T{}, QS) &&
|
||||
QuantitySpec<T> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> && implicitly_convertible(T{}, QS) &&
|
||||
// the below is to make the following work
|
||||
// static_assert(ReferenceOf<si::radian, isq::angular_measure>);
|
||||
// static_assert(!ReferenceOf<si::radian, dimensionless>);
|
||||
|
@ -38,7 +38,7 @@ namespace mp_units {
|
||||
namespace detail {
|
||||
|
||||
template<QuantitySpec auto Q, Unit auto U>
|
||||
using reference_t = reference<std::remove_const_t<decltype(Q)>, std::remove_const_t<decltype(U)>>;
|
||||
using reference_t = reference<MP_UNITS_REMOVE_CONST(decltype(Q)), MP_UNITS_REMOVE_CONST(decltype(U))>;
|
||||
|
||||
}
|
||||
|
||||
@ -258,13 +258,13 @@ MP_UNITS_EXPORT_END
|
||||
namespace detail {
|
||||
|
||||
template<AssociatedUnit auto To, AssociatedUnit From>
|
||||
[[nodiscard]] consteval std::remove_const_t<decltype(To)> clone_reference_with(From)
|
||||
[[nodiscard]] consteval MP_UNITS_REMOVE_CONST(decltype(To)) clone_reference_with(From)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
template<Unit auto To, QuantitySpec QS, Unit U>
|
||||
[[nodiscard]] consteval reference<QS, std::remove_const_t<decltype(To)>> clone_reference_with(reference<QS, U>)
|
||||
[[nodiscard]] consteval reference<QS, MP_UNITS_REMOVE_CONST(decltype(To))> clone_reference_with(reference<QS, U>)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ template<typename Q, typename U>
|
||||
* the provided quantity_spec type.
|
||||
*/
|
||||
template<typename T, auto QS>
|
||||
concept ReferenceOf = Reference<T> && QuantitySpecOf<std::remove_const_t<decltype(get_quantity_spec(T{}))>, QS>;
|
||||
concept ReferenceOf = Reference<T> && QuantitySpecOf<decltype(get_quantity_spec(T{})), QS>;
|
||||
|
||||
MP_UNITS_EXPORT_END
|
||||
|
||||
|
@ -26,10 +26,11 @@
|
||||
// IWYU pragma: private, include <mp-units/framework.h>
|
||||
#include <mp-units/bits/hacks.h>
|
||||
#include <mp-units/bits/module_macros.h>
|
||||
#include <mp-units/compat_macros.h>
|
||||
#include <mp-units/ext/algorithm.h>
|
||||
#include <mp-units/ext/fixed_string.h>
|
||||
|
||||
#ifndef MP_UNITS_IN_MODULE_INTERFACE
|
||||
#include <gsl/gsl-lite.hpp>
|
||||
#include <compare> // IWYU pragma: export
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
@ -85,41 +86,42 @@ constexpr fixed_u8string<N> to_u8string(fixed_string<N> txt)
|
||||
* @tparam M The size of the ASCII-only symbol
|
||||
*/
|
||||
MP_UNITS_EXPORT template<std::size_t N, std::size_t M>
|
||||
struct symbol_text {
|
||||
class symbol_text {
|
||||
public:
|
||||
fixed_u8string<N> unicode_;
|
||||
fixed_string<M> ascii_;
|
||||
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
constexpr explicit(false) symbol_text(char ch) : unicode_(static_cast<char8_t>(ch)), ascii_(ch)
|
||||
{
|
||||
gsl_Expects(detail::is_basic_literal_character_set_char(ch));
|
||||
MP_UNITS_EXPECTS(detail::is_basic_literal_character_set_char(ch));
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(*-avoid-c-arrays, google-explicit-constructor, hicpp-explicit-conversions)
|
||||
constexpr explicit(false) symbol_text(const char (&txt)[N + 1]) :
|
||||
consteval explicit(false) symbol_text(const char (&txt)[N + 1]) :
|
||||
unicode_(detail::to_u8string(basic_fixed_string{txt})), ascii_(txt)
|
||||
{
|
||||
gsl_Expects(txt[N] == char{});
|
||||
gsl_Expects(detail::is_basic_literal_character_set(txt));
|
||||
MP_UNITS_EXPECTS(txt[N] == char{});
|
||||
MP_UNITS_EXPECTS(detail::is_basic_literal_character_set(txt));
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
|
||||
constexpr explicit(false) symbol_text(const fixed_string<N>& txt) : unicode_(detail::to_u8string(txt)), ascii_(txt)
|
||||
{
|
||||
gsl_Expects(detail::is_basic_literal_character_set(txt.data_));
|
||||
MP_UNITS_EXPECTS(detail::is_basic_literal_character_set(txt.data_));
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(*-avoid-c-arrays)
|
||||
constexpr symbol_text(const char8_t (&u)[N + 1], const char (&a)[M + 1]) : unicode_(u), ascii_(a)
|
||||
consteval symbol_text(const char8_t (&u)[N + 1], const char (&a)[M + 1]) : unicode_(u), ascii_(a)
|
||||
{
|
||||
gsl_Expects(u[N] == char8_t{});
|
||||
gsl_Expects(a[M] == char{});
|
||||
gsl_Expects(detail::is_basic_literal_character_set(a));
|
||||
MP_UNITS_EXPECTS(u[N] == char8_t{});
|
||||
MP_UNITS_EXPECTS(a[M] == char{});
|
||||
MP_UNITS_EXPECTS(detail::is_basic_literal_character_set(a));
|
||||
}
|
||||
|
||||
constexpr symbol_text(const fixed_u8string<N>& u, const fixed_string<M>& a) : unicode_(u), ascii_(a)
|
||||
{
|
||||
gsl_Expects(detail::is_basic_literal_character_set(a.data_));
|
||||
MP_UNITS_EXPECTS(detail::is_basic_literal_character_set(a.data_));
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const auto& unicode() const { return unicode_; }
|
||||
@ -127,7 +129,7 @@ struct symbol_text {
|
||||
|
||||
[[nodiscard]] constexpr bool empty() const
|
||||
{
|
||||
gsl_AssertDebug(unicode().empty() == ascii().empty());
|
||||
MP_UNITS_ASSERT_DEBUG(unicode().empty() == ascii().empty());
|
||||
return unicode().empty();
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ namespace mp_units {
|
||||
* @tparam CoU coherent unit for a quantity in this system
|
||||
*/
|
||||
template<QuantitySpec auto Q, Unit auto CoU>
|
||||
requires(!AssociatedUnit<std::remove_const_t<decltype(CoU)>>) || (CoU == one)
|
||||
requires(!AssociatedUnit<decltype(CoU)>) || (CoU == one)
|
||||
struct system_reference {
|
||||
static constexpr auto quantity_spec = Q;
|
||||
static constexpr auto coherent_unit = CoU;
|
||||
@ -68,9 +68,9 @@ struct system_reference {
|
||||
template<Unit U>
|
||||
requires(convertible(coherent_unit, U{}))
|
||||
#if MP_UNITS_COMP_MSVC
|
||||
[[nodiscard]] constexpr decltype(reference<std::remove_const_t<decltype(quantity_spec)>, U>{}) operator[](U) const
|
||||
[[nodiscard]] constexpr decltype(reference<MP_UNITS_REMOVE_CONST(decltype(Q)), U>{}) operator[](U) const
|
||||
#else
|
||||
[[nodiscard]] constexpr reference<std::remove_const_t<decltype(quantity_spec)>, U> operator[](U) const
|
||||
[[nodiscard]] constexpr reference<MP_UNITS_REMOVE_CONST(decltype(Q)), U> operator[](U) const
|
||||
#endif
|
||||
{
|
||||
return {};
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <mp-units/bits/module_macros.h>
|
||||
#include <mp-units/bits/ratio.h>
|
||||
#include <mp-units/bits/text_tools.h>
|
||||
#include <mp-units/compat_macros.h>
|
||||
#include <mp-units/ext/algorithm.h>
|
||||
#include <mp-units/ext/fixed_string.h>
|
||||
#include <mp-units/ext/type_name.h>
|
||||
@ -40,12 +41,13 @@
|
||||
#include <mp-units/framework/unit_concepts.h>
|
||||
|
||||
#ifndef MP_UNITS_IN_MODULE_INTERFACE
|
||||
#include <gsl/gsl-lite.hpp>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#if MP_UNITS_HOSTED
|
||||
#include <string>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace mp_units {
|
||||
@ -173,13 +175,13 @@ struct named_unit<Symbol> {
|
||||
*/
|
||||
template<symbol_text Symbol, Unit auto U>
|
||||
requires(!Symbol.empty())
|
||||
struct named_unit<Symbol, U> : std::remove_const_t<decltype(U)> {
|
||||
struct named_unit<Symbol, U> : decltype(U) {
|
||||
static constexpr auto symbol = Symbol; ///< Unique unit identifier
|
||||
};
|
||||
|
||||
template<symbol_text Symbol, Unit auto U, PointOrigin auto PO>
|
||||
requires(!Symbol.empty())
|
||||
struct named_unit<Symbol, U, PO> : std::remove_const_t<decltype(U)> {
|
||||
struct named_unit<Symbol, U, PO> : decltype(U) {
|
||||
static constexpr auto symbol = Symbol; ///< Unique unit identifier
|
||||
static constexpr auto point_origin = PO;
|
||||
};
|
||||
@ -195,14 +197,14 @@ struct named_unit<Symbol, U, PO> : std::remove_const_t<decltype(U)> {
|
||||
*/
|
||||
template<symbol_text Symbol, AssociatedUnit auto U, detail::QuantityKindSpec auto QS>
|
||||
requires(!Symbol.empty()) && (QS.dimension == detail::get_associated_quantity(U).dimension)
|
||||
struct named_unit<Symbol, U, QS> : std::remove_const_t<decltype(U)> {
|
||||
struct named_unit<Symbol, U, QS> : decltype(U) {
|
||||
static constexpr auto symbol = Symbol; ///< Unique unit identifier
|
||||
static constexpr auto quantity_spec = QS;
|
||||
};
|
||||
|
||||
template<symbol_text Symbol, AssociatedUnit auto U, detail::QuantityKindSpec auto QS, PointOrigin auto PO>
|
||||
requires(!Symbol.empty()) && (QS.dimension == detail::get_associated_quantity(U).dimension)
|
||||
struct named_unit<Symbol, U, QS, PO> : std::remove_const_t<decltype(U)> {
|
||||
struct named_unit<Symbol, U, QS, PO> : decltype(U) {
|
||||
static constexpr auto symbol = Symbol; ///< Unique unit identifier
|
||||
static constexpr auto quantity_spec = QS;
|
||||
static constexpr auto point_origin = PO;
|
||||
@ -232,7 +234,7 @@ struct named_unit<Symbol, U, QS, PO> : std::remove_const_t<decltype(U)> {
|
||||
*/
|
||||
MP_UNITS_EXPORT template<symbol_text Symbol, Magnitude auto M, PrefixableUnit auto U>
|
||||
requires(!Symbol.empty())
|
||||
struct prefixed_unit : std::remove_const_t<decltype(M * U)> {
|
||||
struct prefixed_unit : decltype(M * U) {
|
||||
static constexpr auto symbol = Symbol + U.symbol;
|
||||
};
|
||||
|
||||
@ -390,7 +392,7 @@ template<typename T, typename F, int Num, int... Den>
|
||||
return canonical_unit{pow<Num, Den...>(base.mag) * num.mag / den.mag, num.reference_unit / den.reference_unit};
|
||||
} else {
|
||||
return canonical_unit{pow<Num, Den...>(base.mag),
|
||||
derived_unit<power<std::remove_const_t<decltype(base.reference_unit)>, Num, Den...>>{}};
|
||||
derived_unit<power<decltype(base.reference_unit), Num, Den...>>{}};
|
||||
}
|
||||
}
|
||||
|
||||
@ -430,9 +432,9 @@ MP_UNITS_EXPORT_BEGIN
|
||||
* Multiplication by `1` returns the same unit, otherwise `scaled_unit` is being returned.
|
||||
*/
|
||||
template<Magnitude M, Unit U>
|
||||
[[nodiscard]] MP_UNITS_CONSTEVAL Unit auto operator*(M, const U u)
|
||||
[[nodiscard]] MP_UNITS_CONSTEVAL Unit auto operator*(M, U u)
|
||||
{
|
||||
if constexpr (std::is_same_v<M, std::remove_cvref_t<decltype(mp_units::mag<1>)>>)
|
||||
if constexpr (std::is_same_v<M, std::remove_const_t<decltype(mp_units::mag<1>)>>)
|
||||
return u;
|
||||
else
|
||||
return scaled_unit<M{}, U>{};
|
||||
@ -444,7 +446,7 @@ template<Magnitude M, Unit U>
|
||||
* Returns the result of multiplication with an inverse unit.
|
||||
*/
|
||||
template<Magnitude M, Unit U>
|
||||
[[nodiscard]] MP_UNITS_CONSTEVAL Unit auto operator/(M mag, const U u)
|
||||
[[nodiscard]] MP_UNITS_CONSTEVAL Unit auto operator/(M mag, U u)
|
||||
{
|
||||
return mag * inverse(u);
|
||||
}
|
||||
@ -571,7 +573,7 @@ template<std::intmax_t Num, std::intmax_t Den = 1, Unit U>
|
||||
else if constexpr (detail::ratio{Num, Den} == 1)
|
||||
return u;
|
||||
else if constexpr (detail::is_specialization_of_scaled_unit<U>)
|
||||
return scaled_unit<pow<Num, Den>(U::mag), std::remove_const_t<decltype(pow<Num, Den>(U::reference_unit))>>{};
|
||||
return scaled_unit<pow<Num, Den>(U::mag), decltype(pow<Num, Den>(U::reference_unit))>{};
|
||||
else if constexpr (detail::is_specialization_of_derived_unit<U>)
|
||||
return detail::expr_pow<Num, Den, derived_unit, struct one, detail::type_list_of_unit_less>(u);
|
||||
else if constexpr (Den == 1)
|
||||
@ -657,7 +659,7 @@ template<Unit U1, Unit U2>
|
||||
return u1;
|
||||
else {
|
||||
constexpr auto cm = detail::common_magnitude(canonical_lhs.mag, canonical_rhs.mag);
|
||||
return scaled_unit<cm, std::remove_const_t<decltype(canonical_lhs.reference_unit)>>{};
|
||||
return scaled_unit<cm, decltype(canonical_lhs.reference_unit)>{};
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -718,8 +720,8 @@ constexpr Out print_separator(Out out, const unit_symbol_formatting& fmt)
|
||||
{
|
||||
if (fmt.separator == unit_symbol_separator::half_high_dot) {
|
||||
if (fmt.encoding != text_encoding::unicode)
|
||||
throw std::invalid_argument(
|
||||
"'unit_symbol_separator::half_high_dot' can be only used with 'text_encoding::unicode'");
|
||||
MP_UNITS_THROW(
|
||||
std::invalid_argument("'unit_symbol_separator::half_high_dot' can be only used with 'text_encoding::unicode'"));
|
||||
const std::string_view dot = "⋅";
|
||||
out = detail::copy(dot.begin(), dot.end(), out);
|
||||
} else {
|
||||
@ -808,7 +810,8 @@ template<typename CharT, std::output_iterator<CharT> Out, typename... Expr>
|
||||
constexpr Out unit_symbol_impl(Out out, const derived_unit<Expr...>&, const unit_symbol_formatting& fmt,
|
||||
bool negative_power)
|
||||
{
|
||||
gsl_Expects(negative_power == false);
|
||||
(void)negative_power;
|
||||
MP_UNITS_EXPECTS(negative_power == false);
|
||||
return unit_symbol_impl<CharT>(out, typename derived_unit<Expr...>::_num_{}, typename derived_unit<Expr...>::_den_{},
|
||||
fmt);
|
||||
}
|
||||
@ -843,9 +846,15 @@ MP_UNITS_EXPORT template<unit_symbol_formatting fmt = unit_symbol_formatting{},
|
||||
#endif
|
||||
{
|
||||
auto get_size = []() consteval {
|
||||
#if MP_UNITS_HOSTED
|
||||
std::basic_string<CharT> buffer;
|
||||
unit_symbol_to<CharT>(std::back_inserter(buffer), U{}, fmt);
|
||||
return buffer.size();
|
||||
#else
|
||||
std::array<CharT, 128> buffer; // TODO unsafe
|
||||
auto end = unit_symbol_to<CharT>(buffer.begin(), U{}, fmt);
|
||||
return end - buffer.begin();
|
||||
#endif
|
||||
};
|
||||
|
||||
#if MP_UNITS_API_STRING_VIEW_RET // Permitting static constexpr variables in constexpr functions
|
||||
@ -854,8 +863,7 @@ MP_UNITS_EXPORT template<unit_symbol_formatting fmt = unit_symbol_formatting{},
|
||||
return std::string_view(buffer.data(), size);
|
||||
#else
|
||||
constexpr std::size_t size = get_size();
|
||||
constexpr auto buffer = detail::get_symbol_buffer<CharT, size, fmt>(U{});
|
||||
return basic_fixed_string<CharT, size>(buffer.begin(), buffer.end());
|
||||
return basic_fixed_string(std::from_range, detail::get_symbol_buffer<CharT, size, fmt>(U{}));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -190,7 +190,7 @@ concept AssociatedUnit = Unit<U> && detail::has_associated_quantity(U{});
|
||||
*/
|
||||
MP_UNITS_EXPORT template<typename U, auto QS>
|
||||
concept UnitOf =
|
||||
AssociatedUnit<U> && QuantitySpec<std::remove_const_t<decltype(QS)>> &&
|
||||
AssociatedUnit<U> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> &&
|
||||
implicitly_convertible(get_quantity_spec(U{}), QS) &&
|
||||
// the below is to make `dimensionless[radian]` invalid
|
||||
(get_kind(QS) == get_kind(get_quantity_spec(U{})) || !detail::NestedQuantityKindSpecOf<get_quantity_spec(U{}), QS>);
|
||||
@ -209,7 +209,7 @@ namespace detail {
|
||||
*/
|
||||
MP_UNITS_EXPORT template<typename U, auto U2, auto QS>
|
||||
concept UnitCompatibleWith =
|
||||
Unit<U> && Unit<std::remove_const_t<decltype(U2)>> && QuantitySpec<std::remove_const_t<decltype(QS)>> &&
|
||||
Unit<U> && Unit<MP_UNITS_REMOVE_CONST(decltype(U2))> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> &&
|
||||
(!AssociatedUnit<U> || UnitOf<U, QS>)&&detail::have_same_canonical_reference_unit(U{}, U2);
|
||||
|
||||
|
||||
|
@ -22,6 +22,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mp-units/bits/requires_hosted.h>
|
||||
//
|
||||
#include <mp-units/bits/module_macros.h>
|
||||
#include <mp-units/framework/customization_points.h>
|
||||
#include <mp-units/framework/quantity.h>
|
||||
@ -237,6 +239,29 @@ template<auto R, auto S, auto T, typename Rep1, typename Rep2, typename Rep3>
|
||||
common_reference(R * S, T)};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Computes the fma of 2 quantities and a quantity point
|
||||
*
|
||||
* @param a: Multiplicand
|
||||
* @param x: Multiplicand
|
||||
* @param b: Addend
|
||||
* @return QuantityPoint: The nearest floating point representable to ax+b
|
||||
*/
|
||||
template<auto R, auto S, auto T, auto Origin, typename Rep1, typename Rep2, typename Rep3>
|
||||
requires requires { common_quantity_spec(get_quantity_spec(R) * get_quantity_spec(S), get_quantity_spec(T)); } &&
|
||||
(get_unit(R) * get_unit(S) == get_unit(T)) && requires(Rep1 v1, Rep2 v2, Rep3 v3) {
|
||||
requires requires { fma(v1, v2, v3); } || requires { std::fma(v1, v2, v3); };
|
||||
}
|
||||
[[nodiscard]] constexpr QuantityPointOf<
|
||||
common_quantity_spec(get_quantity_spec(R) * get_quantity_spec(S),
|
||||
get_quantity_spec(T))> auto fma(const quantity<R, Rep1>& a, const quantity<S, Rep2>& x,
|
||||
const quantity_point<T, Origin, Rep3>& b) noexcept
|
||||
{
|
||||
using std::fma;
|
||||
return Origin + quantity{fma(a.numerical_value_ref_in(a.unit), x.numerical_value_ref_in(x.unit),
|
||||
b.quantity_ref_from(b.point_origin).numerical_value_ref_in(b.unit)),
|
||||
common_reference(R * S, T)};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Computes the floating-point remainder of the division operation x / y.
|
||||
|
@ -23,6 +23,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mp-units/bits/requires_hosted.h>
|
||||
//
|
||||
#include <mp-units/bits/module_macros.h>
|
||||
#include <mp-units/framework/quantity.h>
|
||||
#include <mp-units/framework/unit.h>
|
||||
|
@ -8,8 +8,11 @@ export module mp_units.core;
|
||||
|
||||
#include <mp-units/compat_macros.h>
|
||||
#include <mp-units/concepts.h>
|
||||
#include <mp-units/format.h>
|
||||
#include <mp-units/framework.h>
|
||||
|
||||
#if MP_UNITS_HOSTED
|
||||
#include <mp-units/format.h>
|
||||
#include <mp-units/math.h>
|
||||
#include <mp-units/ostream.h>
|
||||
#include <mp-units/random.h>
|
||||
#endif
|
||||
|
@ -22,10 +22,14 @@
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
|
||||
if(NOT MP_UNITS_API_STD_FORMAT)
|
||||
if(NOT MP_UNITS_API_FREESTANDING AND NOT MP_UNITS_API_STD_FORMAT)
|
||||
find_dependency(fmt)
|
||||
endif()
|
||||
|
||||
find_dependency(gsl-lite)
|
||||
if(MP_UNITS_API_CONTRACTS STREQUAL "GSL-LITE")
|
||||
find_dependency(gsl-lite)
|
||||
elseif(MP_UNITS_API_CONTRACTS STREQUAL "MS-GSL")
|
||||
find_dependency(Microsoft.GSL)
|
||||
endif()
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/mp-unitsTargets.cmake")
|
||||
|
@ -25,8 +25,7 @@ cmake_minimum_required(VERSION 3.23)
|
||||
add_mp_units_module(
|
||||
systems mp-units-systems
|
||||
DEPENDENCIES mp-units::core
|
||||
HEADERS include/mp-units/systems/angular/math.h
|
||||
include/mp-units/systems/angular/units.h
|
||||
HEADERS include/mp-units/systems/angular/units.h
|
||||
include/mp-units/systems/iec80000/binary_prefixes.h
|
||||
include/mp-units/systems/iec80000/quantities.h
|
||||
include/mp-units/systems/iec80000/unit_symbols.h
|
||||
@ -39,9 +38,7 @@ add_mp_units_module(
|
||||
include/mp-units/systems/isq/si_quantities.h
|
||||
include/mp-units/systems/isq/space_and_time.h
|
||||
include/mp-units/systems/isq/thermodynamics.h
|
||||
include/mp-units/systems/si/chrono.h
|
||||
include/mp-units/systems/si/constants.h
|
||||
include/mp-units/systems/si/math.h
|
||||
include/mp-units/systems/si/prefixes.h
|
||||
include/mp-units/systems/si/unit_symbols.h
|
||||
include/mp-units/systems/si/units.h
|
||||
@ -60,3 +57,17 @@ add_mp_units_module(
|
||||
include/mp-units/systems/usc.h
|
||||
MODULE_INTERFACE_UNIT mp-units-systems.cpp
|
||||
)
|
||||
|
||||
if(NOT ${projectPrefix}API_FREESTANDING)
|
||||
target_sources(
|
||||
mp-units-systems
|
||||
PUBLIC FILE_SET
|
||||
HEADERS
|
||||
BASE_DIRS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
FILES
|
||||
include/mp-units/systems/angular/math.h
|
||||
include/mp-units/systems/si/math.h
|
||||
include/mp-units/systems/si/chrono.h
|
||||
)
|
||||
endif()
|
||||
|
@ -23,7 +23,9 @@
|
||||
#pragma once
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#if MP_UNITS_HOSTED
|
||||
#include <mp-units/systems/angular/math.h>
|
||||
#endif
|
||||
#include <mp-units/systems/angular/units.h>
|
||||
|
||||
#ifndef MP_UNITS_IN_MODULE_INTERFACE
|
||||
|
@ -22,6 +22,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mp-units/bits/requires_hosted.h>
|
||||
//
|
||||
#include <mp-units/bits/module_macros.h>
|
||||
#include <mp-units/systems/angular/units.h>
|
||||
|
||||
|
@ -42,14 +42,14 @@ template<PrefixableUnit U> struct yobi_ : prefixed_unit<"Yi", mag_power<2, 80>,
|
||||
|
||||
MP_UNITS_EXPORT_BEGIN
|
||||
|
||||
template<PrefixableUnit auto U> inline constexpr kibi_<std::remove_const_t<decltype(U)>> kibi;
|
||||
template<PrefixableUnit auto U> inline constexpr mebi_<std::remove_const_t<decltype(U)>> mebi;
|
||||
template<PrefixableUnit auto U> inline constexpr gibi_<std::remove_const_t<decltype(U)>> gibi;
|
||||
template<PrefixableUnit auto U> inline constexpr tebi_<std::remove_const_t<decltype(U)>> tebi;
|
||||
template<PrefixableUnit auto U> inline constexpr pebi_<std::remove_const_t<decltype(U)>> pebi;
|
||||
template<PrefixableUnit auto U> inline constexpr exbi_<std::remove_const_t<decltype(U)>> exbi;
|
||||
template<PrefixableUnit auto U> inline constexpr zebi_<std::remove_const_t<decltype(U)>> zebi;
|
||||
template<PrefixableUnit auto U> inline constexpr yobi_<std::remove_const_t<decltype(U)>> yobi;
|
||||
template<PrefixableUnit auto U> inline constexpr kibi_<MP_UNITS_REMOVE_CONST(decltype(U))> kibi;
|
||||
template<PrefixableUnit auto U> inline constexpr mebi_<MP_UNITS_REMOVE_CONST(decltype(U))> mebi;
|
||||
template<PrefixableUnit auto U> inline constexpr gibi_<MP_UNITS_REMOVE_CONST(decltype(U))> gibi;
|
||||
template<PrefixableUnit auto U> inline constexpr tebi_<MP_UNITS_REMOVE_CONST(decltype(U))> tebi;
|
||||
template<PrefixableUnit auto U> inline constexpr pebi_<MP_UNITS_REMOVE_CONST(decltype(U))> pebi;
|
||||
template<PrefixableUnit auto U> inline constexpr exbi_<MP_UNITS_REMOVE_CONST(decltype(U))> exbi;
|
||||
template<PrefixableUnit auto U> inline constexpr zebi_<MP_UNITS_REMOVE_CONST(decltype(U))> zebi;
|
||||
template<PrefixableUnit auto U> inline constexpr yobi_<MP_UNITS_REMOVE_CONST(decltype(U))> yobi;
|
||||
// clang-format on
|
||||
|
||||
MP_UNITS_EXPORT_END
|
||||
|
@ -23,9 +23,11 @@
|
||||
#pragma once
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#if MP_UNITS_HOSTED
|
||||
#include <mp-units/systems/si/chrono.h>
|
||||
#include <mp-units/systems/si/constants.h>
|
||||
#include <mp-units/systems/si/math.h>
|
||||
#endif
|
||||
#include <mp-units/systems/si/constants.h>
|
||||
#include <mp-units/systems/si/prefixes.h>
|
||||
#include <mp-units/systems/si/unit_symbols.h>
|
||||
#include <mp-units/systems/si/units.h>
|
||||
|
@ -22,6 +22,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mp-units/bits/requires_hosted.h>
|
||||
//
|
||||
#include <mp-units/bits/module_macros.h>
|
||||
#include <mp-units/systems/isq/si_quantities.h>
|
||||
#include <mp-units/systems/si/prefixes.h>
|
||||
|
@ -22,6 +22,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mp-units/bits/requires_hosted.h>
|
||||
//
|
||||
#include <mp-units/bits/module_macros.h>
|
||||
#include <mp-units/systems/isq/space_and_time.h>
|
||||
#include <mp-units/systems/si/units.h>
|
||||
|
@ -58,30 +58,30 @@ template<PrefixableUnit U> struct quetta_ : prefixed_unit<"Q", mag_power<10, 30>
|
||||
|
||||
MP_UNITS_EXPORT_BEGIN
|
||||
|
||||
template<PrefixableUnit auto U> inline constexpr quecto_<std::remove_const_t<decltype(U)>> quecto;
|
||||
template<PrefixableUnit auto U> inline constexpr ronto_<std::remove_const_t<decltype(U)>> ronto;
|
||||
template<PrefixableUnit auto U> inline constexpr yocto_<std::remove_const_t<decltype(U)>> yocto;
|
||||
template<PrefixableUnit auto U> inline constexpr zepto_<std::remove_const_t<decltype(U)>> zepto;
|
||||
template<PrefixableUnit auto U> inline constexpr atto_<std::remove_const_t<decltype(U)>> atto;
|
||||
template<PrefixableUnit auto U> inline constexpr femto_<std::remove_const_t<decltype(U)>> femto;
|
||||
template<PrefixableUnit auto U> inline constexpr pico_<std::remove_const_t<decltype(U)>> pico;
|
||||
template<PrefixableUnit auto U> inline constexpr nano_<std::remove_const_t<decltype(U)>> nano;
|
||||
template<PrefixableUnit auto U> inline constexpr micro_<std::remove_const_t<decltype(U)>> micro;
|
||||
template<PrefixableUnit auto U> inline constexpr milli_<std::remove_const_t<decltype(U)>> milli;
|
||||
template<PrefixableUnit auto U> inline constexpr centi_<std::remove_const_t<decltype(U)>> centi;
|
||||
template<PrefixableUnit auto U> inline constexpr deci_<std::remove_const_t<decltype(U)>> deci;
|
||||
template<PrefixableUnit auto U> inline constexpr deca_<std::remove_const_t<decltype(U)>> deca;
|
||||
template<PrefixableUnit auto U> inline constexpr hecto_<std::remove_const_t<decltype(U)>> hecto;
|
||||
template<PrefixableUnit auto U> inline constexpr kilo_<std::remove_const_t<decltype(U)>> kilo;
|
||||
template<PrefixableUnit auto U> inline constexpr mega_<std::remove_const_t<decltype(U)>> mega;
|
||||
template<PrefixableUnit auto U> inline constexpr giga_<std::remove_const_t<decltype(U)>> giga;
|
||||
template<PrefixableUnit auto U> inline constexpr tera_<std::remove_const_t<decltype(U)>> tera;
|
||||
template<PrefixableUnit auto U> inline constexpr peta_<std::remove_const_t<decltype(U)>> peta;
|
||||
template<PrefixableUnit auto U> inline constexpr exa_<std::remove_const_t<decltype(U)>> exa;
|
||||
template<PrefixableUnit auto U> inline constexpr zetta_<std::remove_const_t<decltype(U)>> zetta;
|
||||
template<PrefixableUnit auto U> inline constexpr yotta_<std::remove_const_t<decltype(U)>> yotta;
|
||||
template<PrefixableUnit auto U> inline constexpr ronna_<std::remove_const_t<decltype(U)>> ronna;
|
||||
template<PrefixableUnit auto U> inline constexpr quetta_<std::remove_const_t<decltype(U)>> quetta;
|
||||
template<PrefixableUnit auto U> inline constexpr quecto_<MP_UNITS_REMOVE_CONST(decltype(U))> quecto;
|
||||
template<PrefixableUnit auto U> inline constexpr ronto_<MP_UNITS_REMOVE_CONST(decltype(U))> ronto;
|
||||
template<PrefixableUnit auto U> inline constexpr yocto_<MP_UNITS_REMOVE_CONST(decltype(U))> yocto;
|
||||
template<PrefixableUnit auto U> inline constexpr zepto_<MP_UNITS_REMOVE_CONST(decltype(U))> zepto;
|
||||
template<PrefixableUnit auto U> inline constexpr atto_<MP_UNITS_REMOVE_CONST(decltype(U))> atto;
|
||||
template<PrefixableUnit auto U> inline constexpr femto_<MP_UNITS_REMOVE_CONST(decltype(U))> femto;
|
||||
template<PrefixableUnit auto U> inline constexpr pico_<MP_UNITS_REMOVE_CONST(decltype(U))> pico;
|
||||
template<PrefixableUnit auto U> inline constexpr nano_<MP_UNITS_REMOVE_CONST(decltype(U))> nano;
|
||||
template<PrefixableUnit auto U> inline constexpr micro_<MP_UNITS_REMOVE_CONST(decltype(U))> micro;
|
||||
template<PrefixableUnit auto U> inline constexpr milli_<MP_UNITS_REMOVE_CONST(decltype(U))> milli;
|
||||
template<PrefixableUnit auto U> inline constexpr centi_<MP_UNITS_REMOVE_CONST(decltype(U))> centi;
|
||||
template<PrefixableUnit auto U> inline constexpr deci_<MP_UNITS_REMOVE_CONST(decltype(U))> deci;
|
||||
template<PrefixableUnit auto U> inline constexpr deca_<MP_UNITS_REMOVE_CONST(decltype(U))> deca;
|
||||
template<PrefixableUnit auto U> inline constexpr hecto_<MP_UNITS_REMOVE_CONST(decltype(U))> hecto;
|
||||
template<PrefixableUnit auto U> inline constexpr kilo_<MP_UNITS_REMOVE_CONST(decltype(U))> kilo;
|
||||
template<PrefixableUnit auto U> inline constexpr mega_<MP_UNITS_REMOVE_CONST(decltype(U))> mega;
|
||||
template<PrefixableUnit auto U> inline constexpr giga_<MP_UNITS_REMOVE_CONST(decltype(U))> giga;
|
||||
template<PrefixableUnit auto U> inline constexpr tera_<MP_UNITS_REMOVE_CONST(decltype(U))> tera;
|
||||
template<PrefixableUnit auto U> inline constexpr peta_<MP_UNITS_REMOVE_CONST(decltype(U))> peta;
|
||||
template<PrefixableUnit auto U> inline constexpr exa_<MP_UNITS_REMOVE_CONST(decltype(U))> exa;
|
||||
template<PrefixableUnit auto U> inline constexpr zetta_<MP_UNITS_REMOVE_CONST(decltype(U))> zetta;
|
||||
template<PrefixableUnit auto U> inline constexpr yotta_<MP_UNITS_REMOVE_CONST(decltype(U))> yotta;
|
||||
template<PrefixableUnit auto U> inline constexpr ronna_<MP_UNITS_REMOVE_CONST(decltype(U))> ronna;
|
||||
template<PrefixableUnit auto U> inline constexpr quetta_<MP_UNITS_REMOVE_CONST(decltype(U))> quetta;
|
||||
// clang-format on
|
||||
|
||||
MP_UNITS_EXPORT_END
|
||||
|
@ -474,6 +474,32 @@ inline constexpr auto YF = yotta<farad>;
|
||||
inline constexpr auto RF = ronna<farad>;
|
||||
inline constexpr auto QF = quetta<farad>;
|
||||
|
||||
inline constexpr auto qohm = quecto<si::ohm>;
|
||||
inline constexpr auto rohm = ronto<si::ohm>;
|
||||
inline constexpr auto yohm = yocto<si::ohm>;
|
||||
inline constexpr auto zohm = zepto<si::ohm>;
|
||||
inline constexpr auto aohm = atto<si::ohm>;
|
||||
inline constexpr auto fohm = femto<si::ohm>;
|
||||
inline constexpr auto pohm = pico<si::ohm>;
|
||||
inline constexpr auto nohm = nano<si::ohm>;
|
||||
inline constexpr auto uohm = micro<si::ohm>;
|
||||
inline constexpr auto mohm = milli<si::ohm>;
|
||||
inline constexpr auto cohm = centi<si::ohm>;
|
||||
inline constexpr auto dohm = deci<si::ohm>;
|
||||
using si::ohm;
|
||||
inline constexpr auto daohm = deca<si::ohm>;
|
||||
inline constexpr auto hohm = hecto<si::ohm>;
|
||||
inline constexpr auto kohm = kilo<si::ohm>;
|
||||
inline constexpr auto Mohm = mega<si::ohm>;
|
||||
inline constexpr auto Gohm = giga<si::ohm>;
|
||||
inline constexpr auto Tohm = tera<si::ohm>;
|
||||
inline constexpr auto Pohm = peta<si::ohm>;
|
||||
inline constexpr auto Eohm = exa<si::ohm>;
|
||||
inline constexpr auto Zohm = zetta<si::ohm>;
|
||||
inline constexpr auto Yohm = yotta<si::ohm>;
|
||||
inline constexpr auto Rohm = ronna<si::ohm>;
|
||||
inline constexpr auto Qohm = quetta<si::ohm>;
|
||||
|
||||
inline constexpr auto qS = quecto<siemens>;
|
||||
inline constexpr auto rS = ronto<siemens>;
|
||||
inline constexpr auto yS = yocto<siemens>;
|
||||
|
@ -118,7 +118,7 @@ inline constexpr struct troy_pound : named_unit<"lb t", mag<12> * troy_once> {}
|
||||
inline constexpr struct inch_of_mercury : named_unit<"inHg", mag_ratio<3'386'389, 1'000> * si::pascal> {} inch_of_mercury;
|
||||
|
||||
// https://en.wikipedia.org/wiki/United_States_customary_units#Temperature
|
||||
inline constexpr struct zeroth_degree_Fahrenheit : relative_point_origin<si::zeroth_degree_Celsius - 32 * (mag_ratio<5, 9> * si::degree_Celsius)> {} zeroth_degree_Fahrenheit;
|
||||
inline constexpr struct zeroth_degree_Fahrenheit : relative_point_origin<quantity_point{-32 * (mag_ratio<5, 9> * si::degree_Celsius)}> {} zeroth_degree_Fahrenheit;
|
||||
inline constexpr struct degree_Fahrenheit : named_unit<symbol_text{u8"°F", "`F"}, mag_ratio<5, 9> * si::degree_Celsius, zeroth_degree_Fahrenheit> {} degree_Fahrenheit;
|
||||
|
||||
// clang-format on
|
||||
|
@ -22,5 +22,7 @@
|
||||
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
add_subdirectory(runtime)
|
||||
if(NOT ${projectPrefix}API_FREESTANDING)
|
||||
add_subdirectory(runtime)
|
||||
endif()
|
||||
add_subdirectory(static)
|
||||
|
@ -24,7 +24,9 @@ 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 atomic_test.cpp)
|
||||
add_executable(
|
||||
unit_tests_runtime distribution_test.cpp fixed_string_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()
|
||||
|
68
test/runtime/fixed_string_test.cpp
Normal file
68
test/runtime/fixed_string_test.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// 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_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers_exception.hpp>
|
||||
#include <mp-units/compat_macros.h>
|
||||
#include <sstream>
|
||||
#include <string_view>
|
||||
#ifdef MP_UNITS_MODULES
|
||||
import mp_units;
|
||||
#else
|
||||
#include <mp-units/ext/fixed_string.h>
|
||||
#endif
|
||||
|
||||
using namespace mp_units;
|
||||
|
||||
TEST_CASE("fixed_string::at", "[fixed_string]")
|
||||
{
|
||||
basic_fixed_string txt = "abc";
|
||||
SECTION("in range")
|
||||
{
|
||||
CHECK(txt.at(0) == 'a');
|
||||
CHECK(txt.at(1) == 'b');
|
||||
CHECK(txt.at(2) == 'c');
|
||||
}
|
||||
SECTION("out of range")
|
||||
{
|
||||
REQUIRE_THROWS_MATCHES(txt.at(3), std::out_of_range, Catch::Matchers::Message("basic_fixed_string::at"));
|
||||
REQUIRE_THROWS_MATCHES(txt.at(1024), std::out_of_range, Catch::Matchers::Message("basic_fixed_string::at"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("fixed_string text output", "[fixed_string][ostream][fmt]")
|
||||
{
|
||||
basic_fixed_string txt = "units";
|
||||
SECTION("iostream")
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << txt;
|
||||
CHECK(os.str() == "units");
|
||||
}
|
||||
SECTION("fmt") { CHECK(MP_UNITS_STD_FMT::format("{}", txt) == "units"); }
|
||||
}
|
||||
|
||||
TEST_CASE("fixed_string hash", "[fixed_string][hash]")
|
||||
{
|
||||
basic_fixed_string txt = "units";
|
||||
CHECK(std::hash<fixed_string<5>>{}(txt) == std::hash<std::string_view>{}("units"));
|
||||
}
|
@ -34,7 +34,6 @@
|
||||
#ifdef MP_UNITS_MODULES
|
||||
import mp_units;
|
||||
#else
|
||||
#include <mp-units/ext/fixed_string.h>
|
||||
#include <mp-units/format.h>
|
||||
#include <mp-units/ostream.h> // IWYU pragma: keep
|
||||
#include <mp-units/systems/cgs.h>
|
||||
@ -51,18 +50,6 @@ inline constexpr bool mp_units::is_vector<T> = true;
|
||||
using namespace mp_units;
|
||||
using namespace mp_units::si::unit_symbols;
|
||||
|
||||
TEST_CASE("fixed_string", "[text][ostream][fmt]")
|
||||
{
|
||||
basic_fixed_string txt = "units";
|
||||
SECTION("iostream")
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << txt;
|
||||
CHECK(os.str() == "units");
|
||||
}
|
||||
SECTION("fmt") { CHECK(MP_UNITS_STD_FMT::format("{}", txt) == "units"); }
|
||||
}
|
||||
|
||||
TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]")
|
||||
{
|
||||
std::ostringstream os;
|
||||
|
@ -32,7 +32,6 @@ add_library(
|
||||
unit_tests_static
|
||||
angular_test.cpp
|
||||
cgs_test.cpp
|
||||
chrono_test.cpp
|
||||
compare_test.cpp
|
||||
concepts_test.cpp
|
||||
# custom_rep_test_min_expl.cpp
|
||||
@ -40,7 +39,6 @@ add_library(
|
||||
dimension_test.cpp
|
||||
dimension_symbol_test.cpp
|
||||
fixed_string_test.cpp
|
||||
fractional_exponent_quantity.cpp
|
||||
hep_test.cpp
|
||||
iau_test.cpp
|
||||
iec80000_test.cpp
|
||||
@ -49,7 +47,6 @@ add_library(
|
||||
isq_test.cpp
|
||||
isq_angle_test.cpp
|
||||
# magnitude_test.cpp
|
||||
math_test.cpp
|
||||
natural_test.cpp
|
||||
prime_test.cpp
|
||||
quantity_point_test.cpp
|
||||
@ -65,5 +62,10 @@ add_library(
|
||||
usc_test.cpp
|
||||
)
|
||||
|
||||
if(NOT ${projectPrefix}API_FREESTANDING)
|
||||
target_sources(unit_tests_static PRIVATE chrono_test.cpp fractional_exponent_quantity.cpp math_test.cpp)
|
||||
endif()
|
||||
|
||||
target_compile_options(unit_tests_static PRIVATE $<$<CXX_COMPILER_ID:GNU>:-Wno-subobject-linkage>)
|
||||
target_link_libraries(unit_tests_static PRIVATE mp-units::mp-units)
|
||||
target_link_libraries(unit_tests_static PRIVATE unit_tests_static_truncating)
|
||||
|
@ -23,14 +23,18 @@
|
||||
#include <mp-units/systems/isq/space_and_time.h>
|
||||
#include <mp-units/systems/natural.h>
|
||||
#include <mp-units/systems/si.h>
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
#if MP_UNITS_HOSTED
|
||||
#include <chrono>
|
||||
#include <complex>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#endif
|
||||
|
||||
#if MP_UNITS_HOSTED
|
||||
template<typename T>
|
||||
inline constexpr bool mp_units::is_scalar<std::complex<T>> = true;
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
@ -45,9 +49,9 @@ struct dim_speed : decltype(isq::dim_length / isq::dim_time) {};
|
||||
|
||||
// BaseDimension
|
||||
static_assert(detail::BaseDimension<struct isq::dim_length>);
|
||||
static_assert(!detail::BaseDimension<std::remove_const_t<decltype(isq::dim_length / isq::dim_time)>>);
|
||||
static_assert(!detail::BaseDimension<std::remove_const_t<decltype(inverse(isq::dim_time))>>);
|
||||
static_assert(!detail::BaseDimension<std::remove_const_t<decltype(pow<2>(isq::dim_length))>>);
|
||||
static_assert(!detail::BaseDimension<decltype(isq::dim_length / isq::dim_time)>);
|
||||
static_assert(!detail::BaseDimension<decltype(inverse(isq::dim_time))>);
|
||||
static_assert(!detail::BaseDimension<decltype(pow<2>(isq::dim_length))>);
|
||||
static_assert(!detail::BaseDimension<derived_dimension<struct isq::dim_length, per<struct isq::dim_time>>>);
|
||||
static_assert(!detail::BaseDimension<dim_speed>);
|
||||
static_assert(!detail::BaseDimension<base_dimension<"L">>);
|
||||
@ -55,9 +59,9 @@ static_assert(!detail::BaseDimension<struct si::metre>);
|
||||
static_assert(!detail::BaseDimension<int>);
|
||||
|
||||
// DerivedDimension
|
||||
static_assert(detail::DerivedDimension<std::remove_const_t<decltype(isq::dim_length / isq::dim_time)>>);
|
||||
static_assert(detail::DerivedDimension<std::remove_const_t<decltype(inverse(isq::dim_time))>>);
|
||||
static_assert(detail::DerivedDimension<std::remove_const_t<decltype(pow<2>(isq::dim_length))>>);
|
||||
static_assert(detail::DerivedDimension<decltype(isq::dim_length / isq::dim_time)>);
|
||||
static_assert(detail::DerivedDimension<decltype(inverse(isq::dim_time))>);
|
||||
static_assert(detail::DerivedDimension<decltype(pow<2>(isq::dim_length))>);
|
||||
static_assert(detail::DerivedDimension<derived_dimension<struct isq::dim_length, per<struct isq::dim_time>>>);
|
||||
static_assert(detail::DerivedDimension<struct dimension_one>);
|
||||
static_assert(!detail::DerivedDimension<dim_speed>);
|
||||
@ -67,9 +71,9 @@ static_assert(!detail::DerivedDimension<int>);
|
||||
|
||||
// Dimension
|
||||
static_assert(Dimension<struct isq::dim_length>);
|
||||
static_assert(Dimension<std::remove_const_t<decltype(isq::dim_length / isq::dim_time)>>);
|
||||
static_assert(Dimension<std::remove_const_t<decltype(inverse(isq::dim_time))>>);
|
||||
static_assert(Dimension<std::remove_const_t<decltype(pow<2>(isq::dim_length))>>);
|
||||
static_assert(Dimension<decltype(isq::dim_length / isq::dim_time)>);
|
||||
static_assert(Dimension<decltype(inverse(isq::dim_time))>);
|
||||
static_assert(Dimension<decltype(pow<2>(isq::dim_length))>);
|
||||
static_assert(Dimension<derived_dimension<struct isq::dim_length, per<struct isq::dim_time>>>);
|
||||
static_assert(Dimension<struct dimension_one>);
|
||||
static_assert(!Dimension<dim_speed>);
|
||||
@ -86,9 +90,9 @@ struct speed : decltype(isq::length / isq::time) {}; // this is not recommended
|
||||
static_assert(QuantitySpec<struct isq::length>);
|
||||
static_assert(QuantitySpec<struct isq::radius>);
|
||||
static_assert(QuantitySpec<struct isq::speed>);
|
||||
static_assert(QuantitySpec<std::remove_const_t<decltype(kind_of<isq::length>)>>);
|
||||
static_assert(QuantitySpec<std::remove_const_t<decltype(isq::length / isq::time)>>);
|
||||
static_assert(QuantitySpec<std::remove_const_t<decltype(pow<2>(isq::length))>>);
|
||||
static_assert(QuantitySpec<decltype(kind_of<isq::length>)>);
|
||||
static_assert(QuantitySpec<decltype(isq::length / isq::time)>);
|
||||
static_assert(QuantitySpec<decltype(pow<2>(isq::length))>);
|
||||
static_assert(QuantitySpec<struct dimensionless>);
|
||||
static_assert(!QuantitySpec<speed>);
|
||||
static_assert(!QuantitySpec<struct isq::dim_length>);
|
||||
@ -99,8 +103,8 @@ static_assert(detail::NamedQuantitySpec<struct isq::length>);
|
||||
static_assert(detail::NamedQuantitySpec<struct isq::radius>);
|
||||
static_assert(detail::NamedQuantitySpec<struct isq::speed>);
|
||||
static_assert(!detail::NamedQuantitySpec<std::remove_const_t<decltype(kind_of<isq::length>)>>);
|
||||
static_assert(!detail::NamedQuantitySpec<std::remove_const_t<decltype(isq::length / isq::time)>>);
|
||||
static_assert(!detail::NamedQuantitySpec<std::remove_const_t<decltype(pow<2>(isq::length))>>);
|
||||
static_assert(!detail::NamedQuantitySpec<decltype(isq::length / isq::time)>);
|
||||
static_assert(!detail::NamedQuantitySpec<decltype(pow<2>(isq::length))>);
|
||||
static_assert(detail::NamedQuantitySpec<struct dimensionless>);
|
||||
static_assert(!detail::NamedQuantitySpec<speed>);
|
||||
static_assert(!detail::NamedQuantitySpec<struct isq::dim_length>);
|
||||
@ -109,10 +113,10 @@ static_assert(!detail::NamedQuantitySpec<int>);
|
||||
// IntermediateDerivedQuantitySpec
|
||||
static_assert(!detail::IntermediateDerivedQuantitySpec<struct isq::length>);
|
||||
static_assert(!detail::IntermediateDerivedQuantitySpec<struct isq::radius>);
|
||||
static_assert(!detail::IntermediateDerivedQuantitySpec<std::remove_const_t<decltype(kind_of<isq::length>)>>);
|
||||
static_assert(!detail::IntermediateDerivedQuantitySpec<decltype(kind_of<isq::length>)>);
|
||||
static_assert(!detail::IntermediateDerivedQuantitySpec<struct isq::speed>);
|
||||
static_assert(detail::IntermediateDerivedQuantitySpec<std::remove_const_t<decltype(isq::length / isq::time)>>);
|
||||
static_assert(detail::IntermediateDerivedQuantitySpec<std::remove_const_t<decltype(pow<2>(isq::length))>>);
|
||||
static_assert(detail::IntermediateDerivedQuantitySpec<decltype(isq::length / isq::time)>);
|
||||
static_assert(detail::IntermediateDerivedQuantitySpec<decltype(pow<2>(isq::length))>);
|
||||
static_assert(!detail::IntermediateDerivedQuantitySpec<struct dimensionless>);
|
||||
static_assert(!detail::IntermediateDerivedQuantitySpec<speed>);
|
||||
static_assert(!detail::IntermediateDerivedQuantitySpec<struct isq::dim_length>);
|
||||
@ -123,8 +127,8 @@ static_assert(!detail::QuantityKindSpec<struct isq::length>);
|
||||
static_assert(!detail::QuantityKindSpec<struct isq::radius>);
|
||||
static_assert(detail::QuantityKindSpec<std::remove_const_t<decltype(kind_of<isq::length>)>>);
|
||||
static_assert(!detail::QuantityKindSpec<struct isq::speed>);
|
||||
static_assert(!detail::QuantityKindSpec<std::remove_const_t<decltype(isq::length / isq::time)>>);
|
||||
static_assert(!detail::QuantityKindSpec<std::remove_const_t<decltype(pow<2>(isq::length))>>);
|
||||
static_assert(!detail::QuantityKindSpec<decltype(isq::length / isq::time)>);
|
||||
static_assert(!detail::QuantityKindSpec<decltype(pow<2>(isq::length))>);
|
||||
static_assert(!detail::QuantityKindSpec<struct dimensionless>);
|
||||
static_assert(!detail::QuantityKindSpec<speed>);
|
||||
static_assert(!detail::QuantityKindSpec<struct isq::dim_length>);
|
||||
@ -138,13 +142,13 @@ struct metre_per_second : decltype(si::metre / si::second) {};
|
||||
|
||||
static_assert(Unit<struct si::metre>);
|
||||
static_assert(Unit<struct si::kilogram>);
|
||||
static_assert(Unit<std::remove_const_t<decltype(si::kilo<si::gram>)>>);
|
||||
static_assert(Unit<decltype(si::kilo<si::gram>)>);
|
||||
static_assert(Unit<struct natural::electronvolt>);
|
||||
static_assert(Unit<std::remove_const_t<decltype(si::metre / si::second)>>);
|
||||
static_assert(Unit<std::remove_const_t<decltype(inverse(si::second))>>);
|
||||
static_assert(Unit<std::remove_const_t<decltype(mag<10> * si::second)>>);
|
||||
static_assert(Unit<std::remove_const_t<decltype(square(si::metre))>>);
|
||||
static_assert(Unit<std::remove_const_t<decltype(pow<2>(si::metre))>>);
|
||||
static_assert(Unit<decltype(si::metre / si::second)>);
|
||||
static_assert(Unit<decltype(inverse(si::second))>);
|
||||
static_assert(Unit<decltype(mag<10> * si::second)>);
|
||||
static_assert(Unit<decltype(square(si::metre))>);
|
||||
static_assert(Unit<decltype(pow<2>(si::metre))>);
|
||||
static_assert(Unit<struct si::standard_gravity>);
|
||||
static_assert(Unit<scaled_unit<mag<10>, struct si::second>>);
|
||||
static_assert(Unit<metre_per_second>);
|
||||
@ -157,18 +161,20 @@ static_assert(!Unit<named_unit<"?", si::metre, isq::length>>);
|
||||
static_assert(!Unit<prefixed_unit<"?", mag<10>, si::second>>);
|
||||
static_assert(!Unit<struct isq::dim_length>);
|
||||
static_assert(!Unit<int>);
|
||||
#if MP_UNITS_HOSTED
|
||||
static_assert(!Unit<std::chrono::seconds>);
|
||||
#endif
|
||||
|
||||
// NamedUnit
|
||||
static_assert(detail::NamedUnit<struct si::metre>);
|
||||
static_assert(detail::NamedUnit<struct natural::electronvolt>);
|
||||
static_assert(!detail::NamedUnit<struct si::kilogram>);
|
||||
static_assert(!detail::NamedUnit<std::remove_const_t<decltype(si::kilo<si::gram>)>>);
|
||||
static_assert(!detail::NamedUnit<std::remove_const_t<decltype(si::metre / si::second)>>);
|
||||
static_assert(!detail::NamedUnit<std::remove_const_t<decltype(inverse(si::second))>>);
|
||||
static_assert(!detail::NamedUnit<std::remove_const_t<decltype(mag<10> * si::second)>>);
|
||||
static_assert(!detail::NamedUnit<std::remove_const_t<decltype(square(si::metre))>>);
|
||||
static_assert(!detail::NamedUnit<std::remove_const_t<decltype(pow<2>(si::metre))>>);
|
||||
static_assert(!detail::NamedUnit<decltype(si::kilo<si::gram>)>);
|
||||
static_assert(!detail::NamedUnit<decltype(si::metre / si::second)>);
|
||||
static_assert(!detail::NamedUnit<decltype(inverse(si::second))>);
|
||||
static_assert(!detail::NamedUnit<decltype(mag<10> * si::second)>);
|
||||
static_assert(!detail::NamedUnit<decltype(square(si::metre))>);
|
||||
static_assert(!detail::NamedUnit<decltype(pow<2>(si::metre))>);
|
||||
static_assert(detail::NamedUnit<struct si::standard_gravity>);
|
||||
static_assert(!detail::NamedUnit<scaled_unit<mag<10>, struct si::second>>);
|
||||
static_assert(!detail::NamedUnit<metre_per_second>);
|
||||
@ -181,18 +187,20 @@ static_assert(!detail::NamedUnit<named_unit<"?", si::metre, isq::length>>);
|
||||
static_assert(!detail::NamedUnit<prefixed_unit<"?", mag<10>, si::second>>);
|
||||
static_assert(!detail::NamedUnit<struct isq::dim_length>);
|
||||
static_assert(!detail::NamedUnit<int>);
|
||||
#if MP_UNITS_HOSTED
|
||||
static_assert(!detail::NamedUnit<std::chrono::seconds>);
|
||||
#endif
|
||||
|
||||
// PrefixableUnit
|
||||
static_assert(PrefixableUnit<struct si::metre>);
|
||||
static_assert(PrefixableUnit<struct natural::electronvolt>);
|
||||
static_assert(!PrefixableUnit<struct si::kilogram>);
|
||||
static_assert(!PrefixableUnit<std::remove_const_t<decltype(si::kilo<si::gram>)>>);
|
||||
static_assert(!PrefixableUnit<std::remove_const_t<decltype(si::metre / si::second)>>);
|
||||
static_assert(!PrefixableUnit<std::remove_const_t<decltype(inverse(si::second))>>);
|
||||
static_assert(!PrefixableUnit<std::remove_const_t<decltype(mag<10> * si::second)>>);
|
||||
static_assert(!PrefixableUnit<std::remove_const_t<decltype(square(si::metre))>>);
|
||||
static_assert(!PrefixableUnit<std::remove_const_t<decltype(pow<2>(si::metre))>>);
|
||||
static_assert(!PrefixableUnit<decltype(si::kilo<si::gram>)>);
|
||||
static_assert(!PrefixableUnit<decltype(si::metre / si::second)>);
|
||||
static_assert(!PrefixableUnit<decltype(inverse(si::second))>);
|
||||
static_assert(!PrefixableUnit<decltype(mag<10> * si::second)>);
|
||||
static_assert(!PrefixableUnit<decltype(square(si::metre))>);
|
||||
static_assert(!PrefixableUnit<decltype(pow<2>(si::metre))>);
|
||||
static_assert(PrefixableUnit<struct si::standard_gravity>);
|
||||
static_assert(!PrefixableUnit<scaled_unit<mag<10>, struct si::second>>);
|
||||
static_assert(!PrefixableUnit<metre_per_second>);
|
||||
@ -205,18 +213,20 @@ static_assert(!PrefixableUnit<named_unit<"?", si::metre, isq::length>>);
|
||||
static_assert(!PrefixableUnit<prefixed_unit<"?", mag<10>, si::second>>);
|
||||
static_assert(!PrefixableUnit<struct isq::dim_length>);
|
||||
static_assert(!PrefixableUnit<int>);
|
||||
#if MP_UNITS_HOSTED
|
||||
static_assert(!PrefixableUnit<std::chrono::seconds>);
|
||||
#endif
|
||||
|
||||
// AssociatedUnit
|
||||
static_assert(AssociatedUnit<struct si::metre>);
|
||||
static_assert(!AssociatedUnit<struct natural::electronvolt>);
|
||||
static_assert(AssociatedUnit<struct si::kilogram>);
|
||||
static_assert(AssociatedUnit<std::remove_const_t<decltype(si::kilo<si::gram>)>>);
|
||||
static_assert(AssociatedUnit<std::remove_const_t<decltype(si::metre / si::second)>>);
|
||||
static_assert(AssociatedUnit<std::remove_const_t<decltype(inverse(si::second))>>);
|
||||
static_assert(AssociatedUnit<std::remove_const_t<decltype(mag<10> * si::second)>>);
|
||||
static_assert(AssociatedUnit<std::remove_const_t<decltype(square(si::metre))>>);
|
||||
static_assert(AssociatedUnit<std::remove_const_t<decltype(pow<2>(si::metre))>>);
|
||||
static_assert(AssociatedUnit<decltype(si::kilo<si::gram>)>);
|
||||
static_assert(AssociatedUnit<decltype(si::metre / si::second)>);
|
||||
static_assert(AssociatedUnit<decltype(inverse(si::second))>);
|
||||
static_assert(AssociatedUnit<decltype(mag<10> * si::second)>);
|
||||
static_assert(AssociatedUnit<decltype(square(si::metre))>);
|
||||
static_assert(AssociatedUnit<decltype(pow<2>(si::metre))>);
|
||||
static_assert(AssociatedUnit<struct si::standard_gravity>);
|
||||
static_assert(AssociatedUnit<scaled_unit<mag<10>, struct si::second>>);
|
||||
static_assert(AssociatedUnit<metre_per_second>);
|
||||
@ -229,7 +239,9 @@ static_assert(!AssociatedUnit<named_unit<"?", si::metre, isq::length>>);
|
||||
static_assert(!AssociatedUnit<prefixed_unit<"?", mag<10>, si::second>>);
|
||||
static_assert(!AssociatedUnit<struct isq::dim_length>);
|
||||
static_assert(!AssociatedUnit<int>);
|
||||
#if MP_UNITS_HOSTED
|
||||
static_assert(!AssociatedUnit<std::chrono::seconds>);
|
||||
#endif
|
||||
|
||||
// UnitOf
|
||||
static_assert(UnitOf<struct si::metre, isq::length>);
|
||||
@ -248,13 +260,13 @@ static_assert(!UnitOf<struct natural::electronvolt, isq::energy>);
|
||||
|
||||
// Reference
|
||||
static_assert(Reference<struct si::metre>);
|
||||
static_assert(Reference<std::remove_const_t<decltype(si::metre / si::second)>>);
|
||||
static_assert(Reference<std::remove_const_t<decltype(isq::length[si::metre])>>);
|
||||
static_assert(Reference<std::remove_const_t<decltype(isq::radius[si::metre])>>);
|
||||
static_assert(Reference<std::remove_const_t<decltype(isq::radius[si::metre] / isq::time[si::second])>>);
|
||||
static_assert(Reference<decltype(si::metre / si::second)>);
|
||||
static_assert(Reference<decltype(isq::length[si::metre])>);
|
||||
static_assert(Reference<decltype(isq::radius[si::metre])>);
|
||||
static_assert(Reference<decltype(isq::radius[si::metre] / isq::time[si::second])>);
|
||||
static_assert(!Reference<struct natural::electronvolt>);
|
||||
static_assert(!Reference<struct isq::length>);
|
||||
static_assert(!Reference<std::remove_const_t<decltype(kind_of<isq::length>)>>);
|
||||
static_assert(!Reference<decltype(kind_of<isq::length>)>);
|
||||
static_assert(!Reference<struct isq::dim_length>);
|
||||
static_assert(!Reference<int>);
|
||||
|
||||
@ -262,51 +274,57 @@ static_assert(!Reference<int>);
|
||||
static_assert(ReferenceOf<struct si::metre, isq::length>);
|
||||
static_assert(ReferenceOf<struct si::metre, isq::radius>);
|
||||
static_assert(!ReferenceOf<struct si::second, isq::length>);
|
||||
static_assert(ReferenceOf<std::remove_const_t<decltype(isq::length[si::metre])>, isq::length>);
|
||||
static_assert(!ReferenceOf<std::remove_const_t<decltype(isq::length[si::metre])>, isq::radius>);
|
||||
static_assert(ReferenceOf<std::remove_const_t<decltype(isq::radius[si::metre])>, isq::length>);
|
||||
static_assert(ReferenceOf<std::remove_const_t<decltype(isq::radius[si::metre])>, isq::radius>);
|
||||
static_assert(ReferenceOf<decltype(isq::length[si::metre]), isq::length>);
|
||||
static_assert(!ReferenceOf<decltype(isq::length[si::metre]), isq::radius>);
|
||||
static_assert(ReferenceOf<decltype(isq::radius[si::metre]), isq::length>);
|
||||
static_assert(ReferenceOf<decltype(isq::radius[si::metre]), isq::radius>);
|
||||
static_assert(!ReferenceOf<struct si::second, isq::dim_length>);
|
||||
|
||||
static_assert(ReferenceOf<struct one, dimensionless>);
|
||||
static_assert(ReferenceOf<std::remove_const_t<decltype(dimensionless[one])>, dimensionless>);
|
||||
static_assert(ReferenceOf<std::remove_const_t<decltype(isq::rotation[one])>, isq::rotation>);
|
||||
static_assert(ReferenceOf<std::remove_const_t<decltype(isq::rotation[one])>, dimensionless>);
|
||||
static_assert(ReferenceOf<decltype(dimensionless[one]), dimensionless>);
|
||||
static_assert(ReferenceOf<decltype(isq::rotation[one]), isq::rotation>);
|
||||
static_assert(ReferenceOf<decltype(isq::rotation[one]), dimensionless>);
|
||||
static_assert(ReferenceOf<struct si::radian, isq::angular_measure>);
|
||||
static_assert(!ReferenceOf<struct si::radian, dimensionless>);
|
||||
static_assert(ReferenceOf<std::remove_const_t<decltype(isq::angular_measure[si::radian])>, isq::angular_measure>);
|
||||
static_assert(!ReferenceOf<std::remove_const_t<decltype(isq::angular_measure[si::radian])>, dimensionless>);
|
||||
static_assert(ReferenceOf<decltype(isq::angular_measure[si::radian]), isq::angular_measure>);
|
||||
static_assert(!ReferenceOf<decltype(isq::angular_measure[si::radian]), dimensionless>);
|
||||
static_assert(ReferenceOf<struct one, isq::rotation>);
|
||||
static_assert(ReferenceOf<struct one, isq::angular_measure>);
|
||||
static_assert(!ReferenceOf<std::remove_const_t<decltype(dimensionless[one])>, isq::rotation>);
|
||||
static_assert(!ReferenceOf<std::remove_const_t<decltype(dimensionless[one])>, isq::angular_measure>);
|
||||
static_assert(!ReferenceOf<decltype(dimensionless[one]), isq::rotation>);
|
||||
static_assert(!ReferenceOf<decltype(dimensionless[one]), isq::angular_measure>);
|
||||
|
||||
// Representation
|
||||
static_assert(Representation<int>);
|
||||
static_assert(Representation<double>);
|
||||
static_assert(Representation<std::complex<double>>);
|
||||
static_assert(!Representation<bool>);
|
||||
static_assert(!Representation<std::optional<int>>);
|
||||
static_assert(!Representation<std::chrono::seconds>);
|
||||
#if MP_UNITS_HOSTED
|
||||
static_assert(Representation<std::complex<double>>);
|
||||
static_assert(!Representation<std::string>);
|
||||
static_assert(!Representation<std::chrono::seconds>);
|
||||
#endif
|
||||
|
||||
// RepresentationOf
|
||||
static_assert(RepresentationOf<int, quantity_character::scalar>);
|
||||
static_assert(RepresentationOf<double, quantity_character::scalar>);
|
||||
static_assert(RepresentationOf<std::complex<double>, quantity_character::scalar>);
|
||||
static_assert(!RepresentationOf<bool, quantity_character::scalar>);
|
||||
static_assert(!RepresentationOf<std::optional<int>, quantity_character::scalar>);
|
||||
#if MP_UNITS_HOSTED
|
||||
static_assert(RepresentationOf<std::complex<double>, quantity_character::scalar>);
|
||||
static_assert(!RepresentationOf<std::chrono::seconds, quantity_character::scalar>);
|
||||
static_assert(!RepresentationOf<std::string, quantity_character::scalar>);
|
||||
#endif
|
||||
|
||||
// Quantity
|
||||
static_assert(Quantity<quantity<si::metre>>);
|
||||
static_assert(Quantity<quantity<isq::length[si::metre]>>);
|
||||
static_assert(Quantity<quantity<si::metre, int>>);
|
||||
static_assert(Quantity<quantity<isq::length[si::metre], int>>);
|
||||
#if MP_UNITS_HOSTED
|
||||
static_assert(!Quantity<std::chrono::seconds>);
|
||||
#endif
|
||||
static_assert(!Quantity<quantity_point<si::metre, my_origin>>);
|
||||
static_assert(!Quantity<std::remove_const_t<decltype(isq::length[si::metre])>>);
|
||||
static_assert(!Quantity<decltype(isq::length[si::metre])>);
|
||||
|
||||
// QuantityOf
|
||||
static_assert(QuantityOf<quantity<si::metre>, isq::length>);
|
||||
@ -332,8 +350,10 @@ static_assert(!QuantityOf<quantity<dimensionless[one]>, isq::rotation>);
|
||||
static_assert(!QuantityOf<quantity<dimensionless[one]>, isq::angular_measure>);
|
||||
|
||||
// QuantityLike
|
||||
#if MP_UNITS_HOSTED
|
||||
static_assert(QuantityLike<std::chrono::seconds>);
|
||||
static_assert(QuantityLike<std::chrono::hours>);
|
||||
#endif
|
||||
static_assert(!QuantityLike<quantity<isq::time[si::second]>>);
|
||||
static_assert(!QuantityLike<quantity_point<isq::length[si::metre], my_origin>>);
|
||||
static_assert(!QuantityLike<int>);
|
||||
@ -345,12 +365,14 @@ static_assert(QuantityPoint<quantity_point<isq::length[si::metre], my_origin>>);
|
||||
static_assert(QuantityPoint<quantity_point<isq::length[si::metre], my_relative_origin, int>>);
|
||||
static_assert(QuantityPoint<quantity_point<isq::radius[si::metre], my_origin>>);
|
||||
static_assert(QuantityPoint<quantity_point<isq::radius[si::metre], my_relative_origin>>);
|
||||
static_assert(!QuantityPoint<std::remove_const_t<decltype(isq::length[si::metre])>>);
|
||||
static_assert(!QuantityPoint<decltype(isq::length[si::metre])>);
|
||||
static_assert(!QuantityPoint<absolute_point_origin<struct my_origin, isq::length>>);
|
||||
static_assert(!QuantityPoint<struct my_origin>);
|
||||
static_assert(!QuantityPoint<struct my_relative_origin>);
|
||||
#if MP_UNITS_HOSTED
|
||||
static_assert(!QuantityPoint<std::chrono::seconds>);
|
||||
static_assert(!QuantityPoint<std::chrono::time_point<std::chrono::system_clock>>);
|
||||
#endif
|
||||
static_assert(!QuantityPoint<int>);
|
||||
|
||||
// QuantityPointOf
|
||||
@ -383,9 +405,11 @@ static_assert(!PointOrigin<relative_point_origin<my_origin + 42 * si::metre>>);
|
||||
static_assert(!PointOrigin<quantity_point<si::metre, my_origin>>);
|
||||
static_assert(!PointOrigin<quantity_point<isq::length[si::metre], my_origin>>);
|
||||
static_assert(!PointOrigin<quantity_point<isq::radius[si::metre], my_origin>>);
|
||||
static_assert(!PointOrigin<std::remove_const_t<decltype(isq::length[si::metre])>>);
|
||||
static_assert(!PointOrigin<decltype(isq::length[si::metre])>);
|
||||
#if MP_UNITS_HOSTED
|
||||
static_assert(!PointOrigin<std::chrono::seconds>);
|
||||
static_assert(!PointOrigin<std::chrono::time_point<std::chrono::system_clock>>);
|
||||
#endif
|
||||
static_assert(!PointOrigin<int>);
|
||||
|
||||
// PointOriginFor
|
||||
@ -407,14 +431,18 @@ static_assert(!PointOriginFor<quantity_point<isq::radius[si::metre], my_origin>,
|
||||
static_assert(!PointOriginFor<quantity_point<isq::radius[si::metre], my_relative_origin>, isq::length>);
|
||||
static_assert(!PointOriginFor<quantity_point<isq::radius[si::metre], my_relative_origin>, isq::radius>);
|
||||
static_assert(!PointOriginFor<quantity_point<isq::radius[si::metre], my_relative_origin>, isq::time>);
|
||||
static_assert(!PointOriginFor<std::remove_const_t<decltype(isq::length[si::metre])>, isq::length>);
|
||||
static_assert(!PointOriginFor<decltype(isq::length[si::metre]), isq::length>);
|
||||
#if MP_UNITS_HOSTED
|
||||
static_assert(!PointOriginFor<std::chrono::seconds, isq::length>);
|
||||
static_assert(!PointOriginFor<std::chrono::time_point<std::chrono::system_clock>, isq::length>);
|
||||
#endif
|
||||
static_assert(!PointOriginFor<int, isq::length>);
|
||||
|
||||
// QuantityPointLike
|
||||
#if MP_UNITS_HOSTED
|
||||
static_assert(QuantityPointLike<std::chrono::time_point<std::chrono::system_clock>>);
|
||||
static_assert(!QuantityPointLike<std::chrono::seconds>);
|
||||
#endif
|
||||
static_assert(!QuantityPointLike<quantity<isq::time[si::second]>>);
|
||||
static_assert(!QuantityPointLike<quantity_point<si::metre, my_origin>>);
|
||||
static_assert(!QuantityPointLike<int>);
|
||||
|
@ -82,7 +82,7 @@ static_assert(!std::convertible_to<min_impl<double>, quantity<si::metre, min_imp
|
||||
|
||||
// multiply syntax should work
|
||||
template<typename T, auto U>
|
||||
concept creates_quantity = Unit<std::remove_cvref_t<decltype(U)>> && requires { T{} * U; };
|
||||
concept creates_quantity = Unit<decltype(U)> && requires { T{} * U; };
|
||||
|
||||
static_assert(creates_quantity<min_impl<int>, si::metre>);
|
||||
static_assert(creates_quantity<min_impl<double>, si::metre>);
|
||||
|
@ -21,42 +21,161 @@
|
||||
// SOFTWARE.
|
||||
|
||||
#include <mp-units/ext/fixed_string.h>
|
||||
#include <array>
|
||||
#include <string_view>
|
||||
|
||||
using namespace mp_units;
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr std::array array = {'a', 'b', 'c'};
|
||||
|
||||
auto from_string = [] {
|
||||
std::string_view txt = "abc";
|
||||
return fixed_string<3>(std::from_range, txt);
|
||||
};
|
||||
|
||||
auto from_string_iter = [] {
|
||||
std::string_view txt = "abc";
|
||||
return fixed_string<3>(txt.begin(), txt.end());
|
||||
};
|
||||
|
||||
constexpr fixed_string<0> txt0;
|
||||
constexpr basic_fixed_string txt1('a');
|
||||
constexpr basic_fixed_string txt2('a', 'b', 'c');
|
||||
constexpr basic_fixed_string txt3 = "abc";
|
||||
constexpr fixed_string<3> txt4(array.begin(), array.end());
|
||||
constexpr basic_fixed_string txt5(std::from_range, array);
|
||||
constexpr basic_fixed_string txt6(from_string());
|
||||
constexpr basic_fixed_string txt7(from_string_iter());
|
||||
|
||||
constexpr fixed_string<3> txt8(txt2.begin(), txt2.end());
|
||||
constexpr fixed_string<3> txt9(txt2.rbegin(), txt2.rend());
|
||||
|
||||
static_assert(txt0.size() == 0);
|
||||
static_assert(txt1.size() == 1);
|
||||
static_assert(txt2.size() == 3);
|
||||
static_assert(txt3.size() == 3);
|
||||
static_assert(txt4.size() == 3);
|
||||
static_assert(txt5.size() == 3);
|
||||
static_assert(txt6.size() == 3);
|
||||
static_assert(txt7.size() == 3);
|
||||
static_assert(txt8.size() == 3);
|
||||
static_assert(txt9.size() == 3);
|
||||
|
||||
static_assert(txt0.length() == 0);
|
||||
static_assert(txt1.length() == 1);
|
||||
static_assert(txt2.length() == 3);
|
||||
|
||||
static_assert(txt0.max_size() == 0);
|
||||
static_assert(txt1.max_size() == 1);
|
||||
static_assert(txt2.max_size() == 3);
|
||||
|
||||
static_assert(txt0.empty() == true);
|
||||
static_assert(txt1.empty() == false);
|
||||
static_assert(txt2.empty() == false);
|
||||
static_assert(txt3.empty() == false);
|
||||
static_assert(txt4.empty() == false);
|
||||
static_assert(txt5.empty() == false);
|
||||
static_assert(txt6.empty() == false);
|
||||
static_assert(txt7.empty() == false);
|
||||
static_assert(txt8.empty() == false);
|
||||
static_assert(txt9.empty() == false);
|
||||
|
||||
static_assert(txt1[0] == 'a');
|
||||
static_assert(txt2[0] == 'a');
|
||||
static_assert(txt2[1] == 'b');
|
||||
static_assert(txt2[2] == 'c');
|
||||
static_assert(txt9[0] == 'c');
|
||||
static_assert(txt9[1] == 'b');
|
||||
static_assert(txt9[2] == 'a');
|
||||
|
||||
#if MP_UNITS_HOSTED
|
||||
static_assert(txt1.at(0) == 'a');
|
||||
static_assert(txt2.at(0) == 'a');
|
||||
static_assert(txt2.at(1) == 'b');
|
||||
static_assert(txt2.at(2) == 'c');
|
||||
static_assert(txt9.at(0) == 'c');
|
||||
static_assert(txt9.at(1) == 'b');
|
||||
static_assert(txt9.at(2) == 'a');
|
||||
#endif
|
||||
|
||||
static_assert(txt1.front() == 'a');
|
||||
static_assert(txt1.back() == 'a');
|
||||
static_assert(txt2.front() == 'a');
|
||||
static_assert(txt2.back() == 'c');
|
||||
static_assert(txt5.front() == 'a');
|
||||
static_assert(txt5.back() == 'c');
|
||||
static_assert(txt6.front() == 'a');
|
||||
static_assert(txt6.back() == 'c');
|
||||
static_assert(txt7.front() == 'a');
|
||||
static_assert(txt7.back() == 'c');
|
||||
static_assert(txt8.front() == 'a');
|
||||
static_assert(txt8.back() == 'c');
|
||||
static_assert(txt9.front() == 'c');
|
||||
static_assert(txt9.back() == 'a');
|
||||
|
||||
static_assert(std::string_view(txt0.data()) == "");
|
||||
static_assert(std::string_view(txt0.c_str()) == "");
|
||||
static_assert(std::string_view(txt1.data()) == "a");
|
||||
static_assert(std::string_view(txt1.c_str()) == "a");
|
||||
static_assert(std::string_view(txt2.data()) == "abc");
|
||||
static_assert(std::string_view(txt2.c_str()) == "abc");
|
||||
|
||||
static_assert(txt0 == "");
|
||||
static_assert("a" == txt1);
|
||||
static_assert(txt2 == "abc");
|
||||
static_assert(txt3 == "abc");
|
||||
static_assert(txt4 == "abc");
|
||||
static_assert(txt5 == "abc");
|
||||
static_assert(txt6 == "abc");
|
||||
static_assert(txt7 == "abc");
|
||||
static_assert(txt8 == "abc");
|
||||
static_assert(txt9 == "cba");
|
||||
|
||||
static_assert(txt1 == basic_fixed_string("a"));
|
||||
static_assert(txt1 != basic_fixed_string("b"));
|
||||
static_assert(txt1 != basic_fixed_string("aa"));
|
||||
static_assert(txt1 < basic_fixed_string("b"));
|
||||
static_assert(txt1 < basic_fixed_string("aa"));
|
||||
static_assert(txt1 + basic_fixed_string('b') == basic_fixed_string("ab"));
|
||||
static_assert(basic_fixed_string('b') + txt1 == basic_fixed_string("ba"));
|
||||
static_assert(txt1 + basic_fixed_string("bc") == basic_fixed_string("abc"));
|
||||
static_assert(basic_fixed_string("bc") + txt1 == basic_fixed_string("bca"));
|
||||
static_assert(txt1 == "a");
|
||||
static_assert(txt1 != "b");
|
||||
static_assert(txt1 != "aa");
|
||||
static_assert(txt1 < "b");
|
||||
static_assert(txt1 < "aa");
|
||||
|
||||
static_assert(txt1 + basic_fixed_string('b') == "ab");
|
||||
static_assert(basic_fixed_string('b') + txt1 == "ba");
|
||||
static_assert(txt1 + basic_fixed_string("bc") == "abc");
|
||||
static_assert(basic_fixed_string("bc") + txt1 == "bca");
|
||||
static_assert(txt1 + 'b' == "ab");
|
||||
static_assert('b' + txt1 == "ba");
|
||||
static_assert(txt1 + "bc" == "abc");
|
||||
static_assert("bc" + txt1 == "bca");
|
||||
|
||||
constexpr basic_fixed_string txt2("abc");
|
||||
static_assert(txt2.size() == 3);
|
||||
static_assert(txt2[0] == 'a');
|
||||
static_assert(txt2[1] == 'b');
|
||||
static_assert(txt2[2] == 'c');
|
||||
static_assert(txt2 == basic_fixed_string("abc"));
|
||||
static_assert(txt2 != basic_fixed_string("cba"));
|
||||
static_assert(txt2 != basic_fixed_string("abcd"));
|
||||
static_assert(txt2 < basic_fixed_string("b"));
|
||||
static_assert(txt2 > basic_fixed_string("aa"));
|
||||
static_assert(txt2 + basic_fixed_string('d') == basic_fixed_string("abcd"));
|
||||
static_assert(basic_fixed_string('d') + txt2 == basic_fixed_string("dabc"));
|
||||
static_assert(txt2 + basic_fixed_string("def") == basic_fixed_string("abcdef"));
|
||||
static_assert(basic_fixed_string("def") + txt2 == basic_fixed_string("defabc"));
|
||||
static_assert(txt2 == "abc");
|
||||
static_assert(txt2 != "cba");
|
||||
static_assert(txt2 != "abcd");
|
||||
static_assert(txt2 < "b");
|
||||
static_assert(txt2 > "aa");
|
||||
|
||||
#ifndef MP_UNITS_COMP_GCC
|
||||
static_assert(std::string_view(basic_fixed_string("abcd")).find('c') == 2);
|
||||
#endif
|
||||
static_assert(txt2 + basic_fixed_string('d') == "abcd");
|
||||
static_assert(basic_fixed_string('d') + txt2 == "dabc");
|
||||
static_assert(txt2 + basic_fixed_string("def") == "abcdef");
|
||||
static_assert(basic_fixed_string("def") + txt2 == "defabc");
|
||||
static_assert(txt2 + 'd' == "abcd");
|
||||
static_assert('d' + txt2 == "dabc");
|
||||
static_assert(txt2 + "def" == "abcdef");
|
||||
static_assert("def" + txt2 == "defabc");
|
||||
|
||||
static_assert(std::string_view(txt2) == "abc");
|
||||
static_assert(txt2.view() == "abc");
|
||||
static_assert(std::string_view(txt2).find('b') == 1);
|
||||
static_assert(txt2.view().find('b') == 1);
|
||||
|
||||
} // namespace
|
||||
|
@ -20,7 +20,9 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#if MP_UNITS_HOSTED
|
||||
#include <mp-units/math.h> // IWYU pragma: keep
|
||||
#endif
|
||||
#include <mp-units/systems/iau.h>
|
||||
#include <mp-units/systems/isq/space_and_time.h>
|
||||
#include <mp-units/systems/si.h>
|
||||
@ -42,7 +44,7 @@ static_assert(isq::length(1 * LD) == 384'399 * si::kilo<si::metre>);
|
||||
static_assert(isq::length(1 * ly) == 9'460'730'472'580'800 * si::metre);
|
||||
static_assert(isq::length(10'000'000'000 * A) == 1 * si::metre);
|
||||
|
||||
#if __cpp_lib_constexpr_cmath || MP_UNITS_COMP_GCC
|
||||
#if MP_UNITS_HOSTED && (__cpp_lib_constexpr_cmath || MP_UNITS_COMP_GCC)
|
||||
// TODO Should the below work for `1 * pc`? If yes, how to extent the type and how to convert it to a floating-point
|
||||
// representation for comparison purposes?
|
||||
static_assert(round<si::metre>(isq::length(1.L * pc)) == 30'856'775'814'913'673 * si::metre);
|
||||
|
@ -83,7 +83,7 @@ static_assert(Magnitude<decltype(mag<2>)>);
|
||||
static_assert(Magnitude<mag_2_>);
|
||||
|
||||
// is_named_magnitude
|
||||
static_assert(!is_named_magnitude<std::remove_cvref_t<decltype(mag<2>)>>);
|
||||
static_assert(!is_named_magnitude<decltype(mag<2>)>);
|
||||
static_assert(is_named_magnitude<mag_2_>);
|
||||
|
||||
// power_v
|
||||
|
@ -26,20 +26,25 @@
|
||||
#include <mp-units/systems/isq.h>
|
||||
#include <mp-units/systems/si.h>
|
||||
#include <mp-units/systems/usc.h>
|
||||
#include <chrono>
|
||||
#include <concepts>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#if MP_UNITS_HOSTED
|
||||
#include <chrono>
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace mp_units;
|
||||
using namespace mp_units::si::unit_symbols;
|
||||
using namespace mp_units::usc::unit_symbols;
|
||||
|
||||
#if MP_UNITS_HOSTED
|
||||
using namespace std::chrono_literals;
|
||||
using sys_seconds = std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>;
|
||||
#endif
|
||||
|
||||
inline constexpr struct zeroth_length : absolute_point_origin<zeroth_length, isq::length> {
|
||||
} zeroth_length;
|
||||
@ -444,6 +449,7 @@ static_assert(!std::convertible_to<quantity<isq::length[m]>, quantity_point<isq:
|
||||
static_assert(!std::constructible_from<quantity_point<special_height[m]>, quantity<isq::height[m]>>);
|
||||
static_assert(!std::convertible_to<quantity<special_height[m]>, quantity_point<isq::height[m]>>);
|
||||
|
||||
#if MP_UNITS_HOSTED
|
||||
// quantity-like
|
||||
static_assert(!std::constructible_from<quantity_point<si::second>, std::chrono::seconds>);
|
||||
static_assert(!std::convertible_to<std::chrono::seconds, quantity_point<si::second>>);
|
||||
@ -453,7 +459,7 @@ static_assert(!std::convertible_to<std::chrono::seconds, quantity_point<isq::tim
|
||||
|
||||
static_assert(!std::constructible_from<quantity_point<isq::period_duration[s]>, std::chrono::seconds>);
|
||||
static_assert(!std::convertible_to<std::chrono::seconds, quantity_point<isq::period_duration[s]>>);
|
||||
|
||||
#endif
|
||||
|
||||
// ----------------------
|
||||
// explicit point origins
|
||||
@ -499,6 +505,7 @@ static_assert(!std::convertible_to<quantity<special_height[m]>, quantity_point<i
|
||||
static_assert(!std::constructible_from<quantity_point<si::metre, mean_sea_level>, quantity<isq::length[m]>>);
|
||||
static_assert(!std::convertible_to<quantity<isq::length[m]>, quantity_point<si::metre, mean_sea_level>>);
|
||||
|
||||
#if MP_UNITS_HOSTED
|
||||
// quantity-like
|
||||
static_assert(!std::constructible_from<quantity_point<si::second, chrono_point_origin<std::chrono::system_clock>>,
|
||||
std::chrono::seconds>);
|
||||
@ -516,6 +523,7 @@ static_assert(
|
||||
static_assert(
|
||||
!std::convertible_to<std::chrono::seconds,
|
||||
quantity_point<isq::period_duration[s], chrono_point_origin<std::chrono::system_clock>>>);
|
||||
#endif
|
||||
|
||||
|
||||
///////////////////////////////////////
|
||||
@ -775,6 +783,7 @@ static_assert(!std::constructible_from<quantity_point<isq::height[m], other_abso
|
||||
static_assert(!std::convertible_to<quantity_point<isq::height[m], ground_level>,
|
||||
quantity_point<isq::height[m], other_absolute_level>>);
|
||||
|
||||
#if MP_UNITS_HOSTED
|
||||
// quantity-point-like
|
||||
static_assert(
|
||||
std::constructible_from<quantity_point<isq::time[s], chrono_point_origin<std::chrono::system_clock>>, sys_seconds>);
|
||||
@ -786,6 +795,7 @@ static_assert(
|
||||
!std::constructible_from<quantity_point<isq::time[s], chrono_point_origin<std::chrono::steady_clock>>, sys_seconds>);
|
||||
static_assert(
|
||||
!std::convertible_to<sys_seconds, quantity_point<isq::time[s], chrono_point_origin<std::chrono::steady_clock>>>);
|
||||
#endif
|
||||
|
||||
|
||||
//////////////////////////////////
|
||||
@ -889,6 +899,7 @@ static_assert(std::is_same_v<std::remove_const_t<decltype(quantity_point{20 * de
|
||||
static_assert(quantity_point{20 * deg_C}.unit == si::degree_Celsius);
|
||||
static_assert(quantity_point{20 * deg_C}.quantity_spec == kind_of<isq::thermodynamic_temperature>);
|
||||
|
||||
#if MP_UNITS_HOSTED
|
||||
using namespace std::chrono_literals;
|
||||
static_assert(std::is_same_v<decltype(quantity_point{sys_seconds{123s}})::rep, std::chrono::seconds::rep>);
|
||||
static_assert(std::is_same_v<std::remove_const_t<decltype(quantity_point{sys_seconds{123s}}.point_origin)>,
|
||||
@ -897,6 +908,7 @@ static_assert(std::is_same_v<std::remove_const_t<decltype(quantity_point{sys_sec
|
||||
chrono_point_origin_<std::chrono::system_clock>>);
|
||||
static_assert(quantity_point{sys_seconds{24h}}.unit == si::second);
|
||||
static_assert(quantity_point{sys_seconds{24h}}.quantity_spec == kind_of<isq::time>);
|
||||
#endif
|
||||
|
||||
|
||||
////////////
|
||||
|
@ -121,10 +121,10 @@ static_assert(!detail::NamedQuantitySpec<decltype(inverse(time))>);
|
||||
static_assert(detail::IntermediateDerivedQuantitySpec<decltype(inverse(time))>);
|
||||
static_assert(!detail::QuantityKindSpec<decltype(inverse(time))>);
|
||||
|
||||
static_assert(QuantitySpec<kind_of_<std::remove_const_t<decltype(length / time)>>>);
|
||||
static_assert(!detail::NamedQuantitySpec<kind_of_<std::remove_const_t<decltype(length / time)>>>);
|
||||
static_assert(detail::IntermediateDerivedQuantitySpec<kind_of_<std::remove_const_t<decltype(length / time)>>>);
|
||||
static_assert(detail::QuantityKindSpec<kind_of_<std::remove_const_t<decltype(length / time)>>>);
|
||||
static_assert(QuantitySpec<kind_of_<decltype(length / time)>>);
|
||||
static_assert(!detail::NamedQuantitySpec<kind_of_<decltype(length / time)>>);
|
||||
static_assert(detail::IntermediateDerivedQuantitySpec<kind_of_<decltype(length / time)>>);
|
||||
static_assert(detail::QuantityKindSpec<kind_of_<decltype(length / time)>>);
|
||||
|
||||
static_assert(QuantitySpec<decltype(kind_of<length> / kind_of<time>)>);
|
||||
static_assert(!detail::NamedQuantitySpec<decltype(kind_of<length> / kind_of<time>)>);
|
||||
|
@ -27,12 +27,14 @@
|
||||
#include <mp-units/systems/isq/mechanics.h>
|
||||
#include <mp-units/systems/isq/space_and_time.h>
|
||||
#include <mp-units/systems/si.h>
|
||||
#include <chrono>
|
||||
#include <concepts>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#if MP_UNITS_HOSTED
|
||||
#include <chrono>
|
||||
#endif
|
||||
|
||||
template<>
|
||||
inline constexpr bool mp_units::is_vector<int> = true;
|
||||
@ -311,12 +313,13 @@ static_assert(quantity{123. * m}.quantity_spec == kind_of<isq::length>);
|
||||
static_assert(quantity{123. * h}.unit == si::hour);
|
||||
static_assert(quantity{123. * h}.quantity_spec == kind_of<isq::time>);
|
||||
|
||||
#if MP_UNITS_HOSTED
|
||||
using namespace std::chrono_literals;
|
||||
static_assert(std::is_same_v<decltype(quantity{123s})::rep, std::chrono::seconds::rep>);
|
||||
static_assert(std::is_same_v<decltype(quantity{123.s})::rep, long double>);
|
||||
static_assert(quantity{24h}.unit == si::hour);
|
||||
static_assert(quantity{24h}.quantity_spec == kind_of<isq::time>);
|
||||
|
||||
#endif
|
||||
|
||||
////////////////////////
|
||||
// assignment operator
|
||||
@ -403,9 +406,6 @@ static_assert((std::uint8_t{255}* m %= 257 * m).numerical_value_in(m) != [] {
|
||||
return ui %= 257;
|
||||
}());
|
||||
|
||||
// TODO ICE
|
||||
// (https://developercommunity2.visualstudio.com/t/ICE-on-a-constexpr-operator-in-mp-unit/1302907)
|
||||
#ifndef MP_UNITS_COMP_MSVC
|
||||
// clang-17 with modules build on ignores disabling conversion warnings
|
||||
#if !(defined MP_UNITS_COMP_CLANG && MP_UNITS_COMP_CLANG < 18 && defined MP_UNITS_MODULES)
|
||||
// next two lines trigger conversions warnings
|
||||
@ -415,7 +415,6 @@ static_assert((22 * m /= 3.33).numerical_value_in(m) == 6);
|
||||
static_assert((22 * m *= 33.33 * one).numerical_value_in(m) == 733);
|
||||
static_assert((22 * m /= 3.33 * one).numerical_value_in(m) == 6);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
template<template<auto, typename> typename Q>
|
||||
concept invalid_compound_assignments = requires() {
|
||||
@ -745,6 +744,8 @@ static_assert(4 / (2 * one) == 2 * one);
|
||||
static_assert(4 * one / 2 == 2 * one);
|
||||
static_assert(4 * one % (2 * one) == 0 * one);
|
||||
|
||||
static_assert(2 * rad * (2 * rad) == 4 * pow<2>(rad));
|
||||
|
||||
// modulo arithmetics
|
||||
static_assert(5 * h % (120 * min) == 60 * min);
|
||||
static_assert(300 * min % (2 * h) == 60 * min);
|
||||
@ -844,8 +845,8 @@ static_assert(10 * isq::mechanical_energy[J] == 5 * isq::force[N] * (2 * isq::le
|
||||
static_assert(1 * si::si2019::speed_of_light_in_vacuum == 299'792'458 * isq::speed[m / s]);
|
||||
|
||||
// Different named dimensions
|
||||
template</*Reference*/ auto R1, /*Reference*/ auto R2> // TODO Use `Reference` when Clang supports it.
|
||||
concept invalid_comparison = !requires { 2 * R1 == 2 * R2; } && !requires { 2 * R2 == 2 * R1; };
|
||||
template<Reference auto R1, Reference auto R2>
|
||||
inline constexpr bool invalid_comparison = !requires { 2 * R1 == 2 * R2; } && !requires { 2 * R2 == 2 * R1; };
|
||||
static_assert(invalid_comparison<isq::activity[Bq], isq::frequency[Hz]>);
|
||||
|
||||
|
||||
|
@ -98,8 +98,7 @@ static_assert(is_of_type<length[metre], reference<length_, metre_>>);
|
||||
static_assert(is_of_type<kind_of<length>[metre], metre_>);
|
||||
|
||||
static_assert(
|
||||
is_of_type<(length / time)[metre / second],
|
||||
reference<std::remove_const_t<decltype(length / time)>, std::remove_const_t<decltype(metre / second)>>>);
|
||||
is_of_type<(length / time)[metre / second], reference<decltype(length / time), decltype(metre / second)>>);
|
||||
static_assert(is_of_type<(kind_of<length> / kind_of<time>)[metre / second], derived_unit<metre_, per<second_>>>);
|
||||
|
||||
// Unit as a reference
|
||||
|
@ -57,8 +57,7 @@ static_assert(1 * Qm == 1'000'000'000'000'000'000 * Tm);
|
||||
|
||||
// check for invalid prefixes
|
||||
template<template<typename U> typename prefix, auto V1>
|
||||
concept can_not_be_prefixed =
|
||||
Unit<std::remove_const_t<decltype(V1)>> && !requires { typename prefix<std::remove_const_t<decltype(V1)>>; };
|
||||
concept can_not_be_prefixed = Unit<decltype(V1)> && !requires { typename prefix<decltype(V1)>; };
|
||||
|
||||
static_assert(can_not_be_prefixed<si::milli_, si::degree_Celsius>);
|
||||
static_assert(can_not_be_prefixed<si::milli_, si::minute>);
|
||||
|
@ -27,7 +27,7 @@
|
||||
#include <type_traits>
|
||||
|
||||
template<auto V, typename T>
|
||||
inline constexpr bool is_of_type = std::is_same_v<std::remove_cvref_t<decltype(V)>, T>;
|
||||
inline constexpr bool is_of_type = std::is_same_v<MP_UNITS_REMOVE_CONST(decltype(V)), T>;
|
||||
|
||||
// NOLINTBEGIN(cppcoreguidelines-macro-usage)
|
||||
#ifdef MP_UNITS_API_NO_CRTP
|
||||
|
@ -210,7 +210,6 @@ static_assert(kilojoule.symbol == "kJ");
|
||||
static_assert(is_of_type<si::kilo<metre>, si::kilo_<metre_>>);
|
||||
static_assert(is_of_type<si::kilo<joule>, si::kilo_<joule_>>);
|
||||
|
||||
// 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_, per<metre_>>>); // !!!
|
||||
|
||||
@ -241,7 +240,6 @@ static_assert(si::yotta<metre>.symbol == "Ym");
|
||||
static_assert(si::ronna<metre>.symbol == "Rm");
|
||||
static_assert(si::quetta<metre>.symbol == "Qm");
|
||||
|
||||
|
||||
// scaled_unit
|
||||
constexpr auto m_1 = mag<1> * metre;
|
||||
static_assert(is_of_type<m_1, metre_>);
|
||||
|
@ -28,3 +28,11 @@ find_package(mp-units REQUIRED)
|
||||
add_executable(test_package test_package.cpp)
|
||||
target_link_libraries(test_package PRIVATE mp-units::mp-units)
|
||||
target_compile_definitions(test_package PRIVATE MP_UNITS_API_STD_FORMAT=$<BOOL:${MP_UNITS_API_STD_FORMAT}>)
|
||||
|
||||
if(MP_UNITS_API_CONTRACTS STREQUAL "NONE")
|
||||
target_compile_definitions(test_package PRIVATE MP_UNITS_API_CONTRACTS=0)
|
||||
elseif(MP_UNITS_API_CONTRACTS STREQUAL "GSL-LITE")
|
||||
target_compile_definitions(test_package PRIVATE MP_UNITS_API_CONTRACTS=2)
|
||||
elseif(MP_UNITS_API_CONTRACTS STREQUAL "MS-GSL")
|
||||
target_compile_definitions(test_package PRIVATE MP_UNITS_API_CONTRACTS=3)
|
||||
endif()
|
||||
|
Reference in New Issue
Block a user