forked from mpusz/mp-units
Merge branch 'master' into chiphogg/docs
This commit is contained in:
75
.github/workflows/ci-conan.yml
vendored
75
.github/workflows/ci-conan.yml
vendored
@@ -41,14 +41,12 @@ jobs:
|
||||
- {
|
||||
name: "Windows MSVC 14.2",
|
||||
os: windows-2019,
|
||||
compiler:
|
||||
{ type: VISUAL, version: 16, std: 20, cc: "cl", cxx: "cl" },
|
||||
compiler: { type: VISUAL, version: 16, cc: "", cxx: "", std: 20 },
|
||||
}
|
||||
- {
|
||||
name: "Windows MSVC 14.3",
|
||||
os: windows-2022,
|
||||
compiler:
|
||||
{ type: MSVC, version: 193, std: 23, cc: "cl", cxx: "cl" },
|
||||
compiler: { type: MSVC, version: 193, cc: "", cxx: "", std: 23 },
|
||||
}
|
||||
- {
|
||||
name: "Ubuntu GCC-10",
|
||||
@@ -140,17 +138,26 @@ jobs:
|
||||
std: 20,
|
||||
},
|
||||
}
|
||||
# In case a Conan docker image will be needed to provide a specific configuration we can use a Docker image as follows
|
||||
# - {
|
||||
# name: "Ubuntu GCC 10.2.0",
|
||||
# os: ubuntu-20.04,
|
||||
# compiler: { type: GCC, version: 10, cc: "gcc-10", cxx: "g++-10" },
|
||||
# docker_image: conanio/gcc10
|
||||
# }
|
||||
build_type: ["Release", "Debug"]
|
||||
downcast_mode: ["on", "auto"]
|
||||
|
||||
env:
|
||||
CC: ${{ matrix.config.compiler.cc }}
|
||||
CXX: ${{ matrix.config.compiler.cxx }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Cache Conan data
|
||||
uses: actions/cache@v2
|
||||
env:
|
||||
cache-name: cache-conan-data
|
||||
with:
|
||||
path: ~/.conan/data
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/metadata.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-build-${{ env.cache-name }}-
|
||||
${{ runner.os }}-build-
|
||||
${{ runner.os }}-
|
||||
- uses: hendrikmuhs/ccache-action@v1
|
||||
if: runner.os == 'Linux'
|
||||
with:
|
||||
@@ -180,8 +187,6 @@ jobs:
|
||||
run: |
|
||||
sudo xcode-select -s "/Applications/Xcode_13.0.app"
|
||||
- name: Install Ninja
|
||||
# TODO Find a proper syntax to make the below work
|
||||
# if: !matrix.config.docker_image
|
||||
shell: bash
|
||||
run: |
|
||||
if [ $RUNNER_OS == 'Linux' ]; then
|
||||
@@ -199,20 +204,21 @@ jobs:
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: "3.8"
|
||||
- name: Install Conan Package Tools
|
||||
- name: Install Conan
|
||||
shell: bash
|
||||
run: |
|
||||
pip install -U conan_package_tools
|
||||
pip install -U conan
|
||||
- name: Configure Conan
|
||||
# TODO Find a proper syntax to make the below work
|
||||
# if: !matrix.config.docker_image
|
||||
shell: bash
|
||||
run: |
|
||||
conan config init
|
||||
conan remote add artifactory https://mpusz.jfrog.io/artifactory/api/conan/conan-oss
|
||||
if [[ "${{ matrix.config.compiler.type }}" == "GCC" || "${{ matrix.config.compiler.type }}" == "CLANG" ]]; then
|
||||
conan profile update settings.compiler.libcxx=${{ matrix.config.lib }} default
|
||||
fi
|
||||
conan profile update settings.compiler.cppstd=${{ matrix.config.compiler.std }} default
|
||||
conan profile update conf.tools.cmake.cmaketoolchain:generator=Ninja default
|
||||
conan profile update settings.build_type=${{ matrix.build_type }} default
|
||||
conan profile update conf.tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" default
|
||||
conan profile show default
|
||||
# - name: Add support for clang-13 to Conan's settings.yml
|
||||
# # TODO Remove when Conan will support clang-13
|
||||
@@ -220,21 +226,22 @@ jobs:
|
||||
# shell: bash
|
||||
# run: |
|
||||
# sed -i -e 's/"8", "9", "10", "11", "12"]/"8", "9", "10", "11", "12", "13"]/' ~/.conan/settings.yml
|
||||
- name: Run Conan Package Tools
|
||||
- name: Set channel
|
||||
shell: bash
|
||||
env:
|
||||
CONAN_USERNAME: mpusz
|
||||
CONAN_OPTIONS: mp-units:build_docs=False,mp-units:downcast_mode=${{ matrix.downcast_mode }}
|
||||
CONAN_UPLOAD: https://mpusz.jfrog.io/artifactory/api/conan/conan-oss
|
||||
CONAN_LOGIN_USERNAME: ${{ secrets.CONAN_LOGIN_USERNAME }}
|
||||
CONAN_PASSWORD: ${{ secrets.CONAN_PASSWORD }}
|
||||
CONAN_CMAKE_GENERATOR: Ninja
|
||||
CONAN_BUILD_TYPES: ${{ matrix.build_type }}
|
||||
CC: ${{ matrix.config.compiler.cc }}
|
||||
CXX: ${{ matrix.config.compiler.cxx }}
|
||||
CONAN_${{ matrix.config.compiler.type }}_VERSIONS: ${{ matrix.config.compiler.version }}
|
||||
run: |
|
||||
if [ ! -z "${{ matrix.config.docker_image }}" ]; then
|
||||
export CONAN_DOCKER_IMAGE=${{ matrix.config.docker_image }}
|
||||
fi
|
||||
python build.py
|
||||
[[ `git tag --contains ${{ github.sha }}` =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] && CHANNEL=stable || CHANNEL=testing
|
||||
echo "CHANNEL=${CHANNEL}" >> ${GITHUB_ENV}
|
||||
- name: Create Conan package
|
||||
shell: bash
|
||||
run: |
|
||||
conan create . mpusz/testing -o mp-units:downcast_mode=${{ matrix.downcast_mode }} -c user.build:all=True -c user.build:skip_docs=True -b mp-units -b outdated -u
|
||||
- name: Upload mp-units Conan package
|
||||
if: github.ref == 'refs/heads/master' || env.CHANNEL == 'stable'
|
||||
shell: bash
|
||||
run: |
|
||||
conan user ${{ secrets.CONAN_LOGIN_USERNAME }} -r artifactory -p ${{ secrets.CONAN_PASSWORD }}
|
||||
conan upload "mp-units*" --all -r artifactory --confirm
|
||||
- name: Remove mp-units package from Conan local cache
|
||||
shell: bash
|
||||
run: |
|
||||
conan remove mp-units -f
|
||||
|
196
.github/workflows/ci-test-package-cmake.yml
vendored
196
.github/workflows/ci-test-package-cmake.yml
vendored
@@ -43,48 +43,91 @@ jobs:
|
||||
matrix:
|
||||
config:
|
||||
- {
|
||||
name: "Windows MSVC 2019",
|
||||
os: windows-latest,
|
||||
compiler: { type: VISUAL, version: 16, cc: "", cxx: "" },
|
||||
name: "Windows MSVC 14.2",
|
||||
os: windows-2019,
|
||||
compiler: { type: VISUAL, version: 16, cc: "", cxx: "", std: 20 },
|
||||
}
|
||||
- {
|
||||
name: "Ubuntu GCC 10.3.0",
|
||||
os: ubuntu-20.04,
|
||||
compiler: { type: GCC, version: 10, cc: "gcc-10", cxx: "g++-10" },
|
||||
lib: "libstdc++11",
|
||||
name: "Windows MSVC 14.3",
|
||||
os: windows-2022,
|
||||
compiler: { type: MSVC, version: 193, cc: "", cxx: "", std: 23 },
|
||||
}
|
||||
- {
|
||||
name: "Ubuntu GCC 11.1.0",
|
||||
os: ubuntu-20.04,
|
||||
compiler: { type: GCC, version: 11, cc: "gcc-11", cxx: "g++-11" },
|
||||
lib: "libstdc++11",
|
||||
}
|
||||
- {
|
||||
name: "Ubuntu Clang 12.0.0 + libstdc++11",
|
||||
name: "Ubuntu GCC-10",
|
||||
os: ubuntu-20.04,
|
||||
compiler:
|
||||
{ type: CLANG, version: 12, cc: "clang-12", cxx: "clang++-12" },
|
||||
{
|
||||
type: GCC,
|
||||
version: 10,
|
||||
cc: "gcc-10",
|
||||
cxx: "g++-10",
|
||||
std: 20,
|
||||
},
|
||||
lib: "libstdc++11",
|
||||
}
|
||||
- {
|
||||
name: "Ubuntu Clang 12.0.0 + libc++",
|
||||
name: "Ubuntu GCC-11",
|
||||
os: ubuntu-20.04,
|
||||
compiler:
|
||||
{ type: CLANG, version: 12, cc: "clang-12", cxx: "clang++-12" },
|
||||
{
|
||||
type: GCC,
|
||||
version: 11,
|
||||
cc: "gcc-11",
|
||||
cxx: "g++-11",
|
||||
std: 20,
|
||||
},
|
||||
lib: "libstdc++11",
|
||||
}
|
||||
- {
|
||||
name: "Ubuntu Clang-12 + libstdc++11",
|
||||
os: ubuntu-20.04,
|
||||
compiler:
|
||||
{
|
||||
type: CLANG,
|
||||
version: 12,
|
||||
cc: "clang-12",
|
||||
cxx: "clang++-12",
|
||||
std: 20,
|
||||
},
|
||||
lib: "libstdc++11",
|
||||
}
|
||||
- {
|
||||
name: "Ubuntu Clang-12 + libc++",
|
||||
os: ubuntu-20.04,
|
||||
compiler:
|
||||
{
|
||||
type: CLANG,
|
||||
version: 12,
|
||||
cc: "clang-12",
|
||||
cxx: "clang++-12",
|
||||
std: 20,
|
||||
},
|
||||
lib: "libc++",
|
||||
}
|
||||
- {
|
||||
name: "Ubuntu Clang 13.0.0 + libc++",
|
||||
name: "Ubuntu Clang-13 + libc++",
|
||||
os: ubuntu-20.04,
|
||||
compiler:
|
||||
{ type: CLANG, version: 13, cc: "clang-13", cxx: "clang++-13" },
|
||||
{
|
||||
type: CLANG,
|
||||
version: 13,
|
||||
cc: "clang-13",
|
||||
cxx: "clang++-13",
|
||||
std: 20,
|
||||
},
|
||||
lib: "libc++",
|
||||
}
|
||||
- {
|
||||
name: "Ubuntu Clang 14.0.0 + libc++",
|
||||
name: "Ubuntu Clang-14 + libc++",
|
||||
os: ubuntu-20.04,
|
||||
compiler:
|
||||
{ type: CLANG, version: 14, cc: "clang-14", cxx: "clang++-14" },
|
||||
{
|
||||
type: CLANG,
|
||||
version: 14,
|
||||
cc: "clang-14",
|
||||
cxx: "clang++-14",
|
||||
std: 20,
|
||||
},
|
||||
lib: "libc++",
|
||||
}
|
||||
- {
|
||||
@@ -96,23 +139,21 @@ jobs:
|
||||
version: "13.0",
|
||||
cc: "clang",
|
||||
cxx: "clang++",
|
||||
std: 20,
|
||||
},
|
||||
}
|
||||
# In case a Conan docker image will be needed to provide a specific configuration we can use a Docker image as follows
|
||||
# - {
|
||||
# name: "Ubuntu GCC 10.2.0",
|
||||
# os: ubuntu-20.04,
|
||||
# compiler: { type: GCC, version: 10, cc: "gcc-10", cxx: "g++-10" },
|
||||
# docker_image: conanio/gcc10
|
||||
# }
|
||||
build_type: ["Release", "Debug"]
|
||||
|
||||
env:
|
||||
CC: ${{ matrix.config.compiler.cc }}
|
||||
CXX: ${{ matrix.config.compiler.cxx }}
|
||||
CMAKE_GENERATOR: Ninja
|
||||
|
||||
steps:
|
||||
- name: Downcase 'build_type'
|
||||
id: build_type
|
||||
uses: ASzc/change-string-case-action@v2
|
||||
with:
|
||||
string: ${{ matrix.build_type }}
|
||||
- uses: actions/checkout@v2
|
||||
- name: Cache Conan data
|
||||
uses: actions/cache@v2
|
||||
@@ -149,8 +190,6 @@ jobs:
|
||||
run: |
|
||||
sudo xcode-select -s "/Applications/Xcode_13.0.app"
|
||||
- name: Install Ninja
|
||||
# TODO Find a proper syntax to make the below work
|
||||
# if: !matrix.config.docker_image
|
||||
shell: bash
|
||||
run: |
|
||||
if [ $RUNNER_OS == 'Linux' ]; then
|
||||
@@ -176,13 +215,13 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
conan config init
|
||||
conan remote add upload https://mpusz.jfrog.io/artifactory/api/conan/conan-oss
|
||||
conan profile update settings.build_type=${{ matrix.build_type }} default
|
||||
conan profile update settings.compiler.cppstd=20 default
|
||||
conan remote add artifactory https://mpusz.jfrog.io/artifactory/api/conan/conan-oss
|
||||
if [[ "${{ matrix.config.compiler.type }}" == "GCC" || "${{ matrix.config.compiler.type }}" == "CLANG" ]]; then
|
||||
conan profile update settings.compiler.libcxx=${{ matrix.config.lib }} default
|
||||
fi
|
||||
conan profile update conf.tools.cmake.cmaketoolchain:generator=Ninja default
|
||||
conan profile update settings.compiler.cppstd=${{ matrix.config.compiler.std }} default
|
||||
conan profile update settings.build_type=${{ matrix.build_type }} default
|
||||
conan profile update conf.tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" default
|
||||
conan profile show default
|
||||
# - name: Add support for clang-13 to Conan's settings.yml
|
||||
# # TODO Remove when Conan will support clang-13
|
||||
@@ -193,63 +232,70 @@ jobs:
|
||||
- name: Install Conan dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p build/${{ matrix.build_type }} && cd build/${{ matrix.build_type }}
|
||||
conan install ../.. -b outdated -u
|
||||
conan install . -b outdated -u
|
||||
mv CMakeUserPresets.json src
|
||||
- name: Configure mp-units CMake
|
||||
if: matrix.config.compiler.type == 'VISUAL'
|
||||
if: matrix.config.compiler.type == 'VISUAL' || matrix.config.compiler.type == 'MSVC'
|
||||
shell: cmd
|
||||
working-directory: build/${{ matrix.build_type }}
|
||||
working-directory: src
|
||||
run: |
|
||||
call conanvcvars.bat
|
||||
cmake ../../src -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
|
||||
cmake --version
|
||||
call ..\build\generators\conanvcvars.bat
|
||||
cmake --preset default -DCMAKE_INSTALL_PREFIX=../out
|
||||
- name: Configure mp-units CMake
|
||||
if: matrix.config.compiler.type != 'VISUAL'
|
||||
if: matrix.config.compiler.type != 'VISUAL' && matrix.config.compiler.type != 'MSVC'
|
||||
shell: bash
|
||||
working-directory: build/${{ matrix.build_type }}
|
||||
working-directory: src
|
||||
run: |
|
||||
cmake ../../src -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
|
||||
cmake --version
|
||||
cmake --preset default -DCMAKE_INSTALL_PREFIX=../out
|
||||
- name: Install mp-units
|
||||
shell: bash
|
||||
working-directory: build/${{ matrix.build_type }}
|
||||
working-directory: src
|
||||
run: |
|
||||
cmake --install . --prefix test_package
|
||||
- name: Install dependencies for test_package
|
||||
cmake --build --preset ${{ steps.build_type.outputs.lowercase }} --target install
|
||||
- name: Provide dependencies for test_package
|
||||
shell: bash
|
||||
working-directory: test_package
|
||||
run: |
|
||||
mkdir -p test_package/build/${{ matrix.build_type }} && cd test_package/build/${{ matrix.build_type }}
|
||||
conan install ../../..
|
||||
cp ../src/CMakeUserPresets.json .
|
||||
- name: Build test_package CMake (local build)
|
||||
if: matrix.config.compiler.type == 'VISUAL'
|
||||
if: matrix.config.compiler.type == 'VISUAL' || matrix.config.compiler.type == 'MSVC'
|
||||
shell: cmd
|
||||
working-directory: test_package/build/${{ matrix.build_type }}
|
||||
working-directory: test_package
|
||||
run: |
|
||||
call conanvcvars.bat
|
||||
cmake ../.. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -Dmp-units_DIR=${{ github.workspace }}/build/${{ matrix.build_type }}
|
||||
cmake --build .
|
||||
call ..\build\generators\conanvcvars.bat
|
||||
cmake --preset default -Dmp-units_DIR=../build -Bbuild/local
|
||||
cmake --build build/local --config ${{ matrix.build_type }}
|
||||
- name: Build test_package CMake (local build)
|
||||
if: matrix.config.compiler.type != 'VISUAL'
|
||||
if: matrix.config.compiler.type != 'VISUAL' && matrix.config.compiler.type != 'MSVC'
|
||||
shell: bash
|
||||
working-directory: test_package/build/${{ matrix.build_type }}
|
||||
working-directory: test_package
|
||||
run: |
|
||||
cmake ../.. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -Dmp-units_DIR=${{ github.workspace }}/build/${{ matrix.build_type }}
|
||||
cmake --build .
|
||||
- name: Build test_package CMake (installation)
|
||||
if: matrix.config.compiler.type == 'VISUAL'
|
||||
shell: cmd
|
||||
working-directory: test_package/build/${{ matrix.build_type }}
|
||||
run: |
|
||||
call conanvcvars.bat
|
||||
cmake ../.. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DCMAKE_INSTALL_PREFIX=../../../build/${{ matrix.build_type }}/test_package
|
||||
cmake --build .
|
||||
- name: Build test_package CMake (installation)
|
||||
if: matrix.config.compiler.type != 'VISUAL'
|
||||
cmake --preset default -Dmp-units_DIR=../build -Bbuild/local
|
||||
cmake --build build/local --config ${{ matrix.build_type }}
|
||||
- name: Run test_package (local build)
|
||||
shell: bash
|
||||
working-directory: test_package/build/${{ matrix.build_type }}
|
||||
run: |
|
||||
cmake ../.. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DCMAKE_INSTALL_PREFIX=../../../build/${{ matrix.build_type }}/test_package
|
||||
cmake --build .
|
||||
- name: Run test_package
|
||||
shell: bash
|
||||
working-directory: test_package/build/${{ matrix.build_type }}
|
||||
working-directory: test_package/build/local/${{ matrix.build_type }}
|
||||
run: |
|
||||
./test_package
|
||||
- name: Build test_package CMake (installation)
|
||||
if: matrix.config.compiler.type == 'VISUAL' || matrix.config.compiler.type == 'MSVC'
|
||||
shell: cmd
|
||||
working-directory: test_package
|
||||
run: |
|
||||
call ..\build\generators\conanvcvars.bat
|
||||
cmake --preset default -DCMAKE_INSTALL_PREFIX=../out -Bbuild/install
|
||||
cmake --build build/install --config ${{ matrix.build_type }}
|
||||
- name: Build test_package CMake (installation)
|
||||
if: matrix.config.compiler.type != 'VISUAL' && matrix.config.compiler.type != 'MSVC'
|
||||
shell: bash
|
||||
working-directory: test_package
|
||||
run: |
|
||||
cmake --preset default -DCMAKE_INSTALL_PREFIX=../out -Bbuild/install
|
||||
cmake --build build/install --config ${{ matrix.build_type }}
|
||||
- name: Run test_package (installation)
|
||||
shell: bash
|
||||
working-directory: test_package/build/install/${{ matrix.build_type }}
|
||||
run: |
|
||||
./test_package
|
||||
|
14
.github/workflows/codeql-analysis.yml
vendored
14
.github/workflows/codeql-analysis.yml
vendored
@@ -16,11 +16,11 @@ on:
|
||||
push:
|
||||
branches: [master]
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- "docs/**"
|
||||
pull_request:
|
||||
branches: [master]
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- "docs/**"
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'cpp', 'python' ]
|
||||
language: ["cpp", "python"]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
||||
# Learn more...
|
||||
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
@@ -56,7 +56,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@v1
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
@@ -77,7 +77,7 @@ jobs:
|
||||
if: matrix.language == 'cpp'
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.8'
|
||||
python-version: "3.8"
|
||||
- name: Conan build
|
||||
if: matrix.language == 'cpp'
|
||||
run: |
|
||||
@@ -85,7 +85,7 @@ jobs:
|
||||
conan config init
|
||||
conan remote add upload https://mpusz.jfrog.io/artifactory/api/conan/conan-oss
|
||||
mkdir _lgtm_build_dir && cd _lgtm_build_dir
|
||||
conan install .. -s compiler.cppstd=20 -s compiler.libcxx=libstdc++11 -o mp-units:build_docs=False -e mp-units:CONAN_RUN_TESTS=True -b outdated -u
|
||||
conan install .. -s compiler.cppstd=20 -s compiler.libcxx=libstdc++11 -c mp-units:user.build:all=True -c user.build:skip_docs=True -b outdated -u
|
||||
conan build ..
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
|
9
.github/workflows/documentation.yml
vendored
9
.github/workflows/documentation.yml
vendored
@@ -78,16 +78,13 @@ jobs:
|
||||
conan remote add -i 0 upload https://mpusz.jfrog.io/artifactory/api/conan/conan-oss
|
||||
- name: Install Conan dependencies
|
||||
run: |
|
||||
mkdir build && cd build
|
||||
conan install .. -s compiler.cppstd=20 -s compiler.libcxx=libstdc++11 -e mp-units:CONAN_RUN_TESTS=True -b outdated -u
|
||||
conan install . -s compiler.cppstd=20 -s compiler.libcxx=libstdc++11 -c user.build:all=True -c tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" -b outdated -u
|
||||
- name: Configure CMake
|
||||
working-directory: build
|
||||
run: |
|
||||
cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release
|
||||
cmake --preset default
|
||||
- name: Generate documentation
|
||||
working-directory: build
|
||||
run: |
|
||||
cmake --build . --target documentation --config Release
|
||||
cmake --build --preset release --target documentation
|
||||
- name: Deploy documentation
|
||||
if: github.ref == 'refs/heads/master'
|
||||
uses: peaceiris/actions-gh-pages@v3
|
||||
|
8
.gitignore
vendored
8
.gitignore
vendored
@@ -46,3 +46,11 @@ CMakeUserPresets.json
|
||||
# Conan
|
||||
*.pyc
|
||||
/test_package/build/
|
||||
|
||||
# Conan internal files
|
||||
# TODO Remove for Conan 2.0
|
||||
conan_paths.cmake
|
||||
conan.lock
|
||||
conanbuildinfo.txt
|
||||
conaninfo.txt
|
||||
graph_info.json
|
||||
|
46
build.py
46
build.py
@@ -1,46 +0,0 @@
|
||||
# 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.
|
||||
|
||||
# The following environment variables are required
|
||||
# - CONAN_USERNAME
|
||||
# - CONAN_UPLOAD
|
||||
# - CONAN_LOGIN_USERNAME
|
||||
# - CONAN_PASSWORD
|
||||
|
||||
from cpt.packager import ConanMultiPackager
|
||||
|
||||
if __name__ == "__main__":
|
||||
builder = ConanMultiPackager(
|
||||
# package id
|
||||
channel="testing",
|
||||
stable_branch_pattern=r"v\d+\.\d+\.\d+.*",
|
||||
# dependencies
|
||||
build_policy=["mp-units", "outdated"],
|
||||
upload_dependencies="all",
|
||||
pip_install=["sphinx", "recommonmark", "breathe"],
|
||||
# build configurations
|
||||
archs=["x86_64"], # limit to 64-bit only
|
||||
)
|
||||
builder.add_common_builds(pure_c=True)
|
||||
for settings, options, env_vars, build_requires, reference in builder.items:
|
||||
env_vars["mp-units:CONAN_RUN_TESTS"] = "True"
|
||||
builder.run()
|
@@ -22,8 +22,8 @@
|
||||
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
find_package(Doxygen MODULE REQUIRED
|
||||
)# TODO Switch to CONFIG when Conan will start supporting imported executables in CMakeDeps
|
||||
# TODO Switch to CONFIG when Conan will start supporting imported executables in CMakeDeps
|
||||
find_package(Doxygen MODULE REQUIRED)
|
||||
find_package(Sphinx REQUIRED)
|
||||
|
||||
#
|
||||
|
69
conanfile.py
69
conanfile.py
@@ -24,15 +24,13 @@ import os
|
||||
import re
|
||||
|
||||
from conan import ConanFile
|
||||
from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain
|
||||
from conan.tools.build import check_min_cppstd
|
||||
from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout
|
||||
from conan.tools.files import copy, load, rmdir
|
||||
from conan.tools.scm import Version
|
||||
from conans.errors import ConanInvalidConfiguration
|
||||
|
||||
# TODO replace with new tools for Conan 2.0
|
||||
from conans.tools import check_min_cppstd, get_env
|
||||
|
||||
required_conan_version = ">=1.48.0"
|
||||
required_conan_version = ">=1.50.0"
|
||||
|
||||
|
||||
class MPUnitsConan(ConanFile):
|
||||
@@ -56,8 +54,8 @@ class MPUnitsConan(ConanFile):
|
||||
url = "https://github.com/mpusz/units"
|
||||
settings = "os", "compiler", "build_type", "arch"
|
||||
requires = "gsl-lite/0.40.0"
|
||||
options = {"downcast_mode": ["off", "on", "auto"], "build_docs": [True, False]}
|
||||
default_options = {"downcast_mode": "on", "build_docs": True}
|
||||
options = {"downcast_mode": ["off", "on", "auto"]}
|
||||
default_options = {"downcast_mode": "on"}
|
||||
exports = ["LICENSE.md"]
|
||||
exports_sources = [
|
||||
"docs/*",
|
||||
@@ -71,8 +69,12 @@ class MPUnitsConan(ConanFile):
|
||||
generators = "cmake_paths"
|
||||
|
||||
@property
|
||||
def _run_tests(self):
|
||||
return get_env("CONAN_RUN_TESTS", False)
|
||||
def _build_all(self):
|
||||
return bool(self.conf["user.build:all"])
|
||||
|
||||
@property
|
||||
def _skip_docs(self):
|
||||
return bool(self.conf["user.build:skip_docs"])
|
||||
|
||||
@property
|
||||
def _use_libfmt(self):
|
||||
@@ -112,10 +114,10 @@ class MPUnitsConan(ConanFile):
|
||||
self.requires("range-v3/0.11.0")
|
||||
|
||||
def build_requirements(self):
|
||||
if self._run_tests:
|
||||
if self._build_all:
|
||||
self.test_requires("catch2/2.13.9")
|
||||
self.test_requires("wg21-linear_algebra/0.7.2")
|
||||
if self.options.build_docs:
|
||||
if not self._skip_docs:
|
||||
self.tool_requires("doxygen/1.9.4")
|
||||
|
||||
# TODO Replace with `valdate()` for Conan 2.0 (https://github.com/conan-io/conan/issues/10723)
|
||||
@@ -145,17 +147,13 @@ class MPUnitsConan(ConanFile):
|
||||
raise ConanInvalidConfiguration("Unsupported compiler")
|
||||
check_min_cppstd(self, 20)
|
||||
|
||||
# TODO Uncomment this when environment is supported in the Conan toolchain
|
||||
# def config_options(self):
|
||||
# if not self._run_tests:
|
||||
# # build_docs has sense only in a development or CI build
|
||||
# del self.options.build_docs
|
||||
def layout(self):
|
||||
cmake_layout(self)
|
||||
|
||||
def generate(self):
|
||||
tc = CMakeToolchain(self)
|
||||
tc.variables["UNITS_DOWNCAST_MODE"] = str(self.options.downcast_mode).upper()
|
||||
# if self._run_tests: # TODO Enable this when environment is supported in the Conan toolchain
|
||||
tc.variables["UNITS_BUILD_DOCS"] = bool(self.options.build_docs)
|
||||
tc.variables["UNITS_BUILD_DOCS"] = self._build_all and not self._skip_docs
|
||||
tc.variables["UNITS_USE_LIBFMT"] = self._use_libfmt
|
||||
tc.generate()
|
||||
deps = CMakeDeps(self)
|
||||
@@ -163,13 +161,13 @@ class MPUnitsConan(ConanFile):
|
||||
|
||||
def build(self):
|
||||
cmake = CMake(self)
|
||||
cmake.configure(build_script_folder=None if self._run_tests else "src")
|
||||
cmake.configure(build_script_folder=None if self._build_all else "src")
|
||||
cmake.build()
|
||||
if self._run_tests:
|
||||
if self._build_all:
|
||||
cmake.test()
|
||||
|
||||
def package_id(self):
|
||||
self.info.header_only()
|
||||
self.info.clear()
|
||||
|
||||
def package(self):
|
||||
copy(
|
||||
@@ -187,7 +185,6 @@ class MPUnitsConan(ConanFile):
|
||||
|
||||
# core
|
||||
self.cpp_info.components["core"].requires = ["gsl-lite::gsl-lite"]
|
||||
self.cpp_info.components["core"].includedirs = ["include"]
|
||||
if compiler == "Visual Studio":
|
||||
self.cpp_info.components["core"].cxxflags = ["/utf-8"]
|
||||
if self._use_range_v3:
|
||||
@@ -195,49 +192,21 @@ class MPUnitsConan(ConanFile):
|
||||
|
||||
# rest
|
||||
self.cpp_info.components["core-io"].requires = ["core"]
|
||||
self.cpp_info.components["core-io"].includedirs = ["include"]
|
||||
|
||||
self.cpp_info.components["core-fmt"].requires = ["core"]
|
||||
self.cpp_info.components["core-fmt"].includedirs = ["include"]
|
||||
if self._use_libfmt:
|
||||
self.cpp_info.components["core-fmt"].requires.append("fmt::fmt")
|
||||
|
||||
self.cpp_info.components["isq"].requires = ["core"]
|
||||
self.cpp_info.components["isq"].includedirs = ["include"]
|
||||
|
||||
self.cpp_info.components["isq-natural"].requires = ["isq"]
|
||||
self.cpp_info.components["isq-natural"].includedirs = ["include"]
|
||||
|
||||
self.cpp_info.components["si"].requires = ["isq"]
|
||||
self.cpp_info.components["si"].includedirs = ["include"]
|
||||
|
||||
self.cpp_info.components["si-cgs"].requires = ["si"]
|
||||
self.cpp_info.components["si-cgs"].includedirs = ["include"]
|
||||
|
||||
self.cpp_info.components["si-fps"].requires = ["si-international"]
|
||||
self.cpp_info.components["si-fps"].includedirs = ["include"]
|
||||
|
||||
self.cpp_info.components["si-hep"].requires = ["si"]
|
||||
self.cpp_info.components["si-hep"].includedirs = ["include"]
|
||||
|
||||
self.cpp_info.components["si-iau"].requires = ["si"]
|
||||
self.cpp_info.components["si-iau"].includedirs = ["include"]
|
||||
|
||||
self.cpp_info.components["si-imperial"].requires = ["si"]
|
||||
self.cpp_info.components["si-imperial"].includedirs = ["include"]
|
||||
|
||||
self.cpp_info.components["si-international"].requires = ["si"]
|
||||
self.cpp_info.components["si-international"].includedirs = ["include"]
|
||||
|
||||
self.cpp_info.components["si-typographic"].requires = ["si"]
|
||||
self.cpp_info.components["si-typographic"].includedirs = ["include"]
|
||||
|
||||
self.cpp_info.components["si-uscs"].requires = ["si"]
|
||||
self.cpp_info.components["si-uscs"].includedirs = ["include"]
|
||||
|
||||
self.cpp_info.components["isq-iec80000"].requires = ["si"]
|
||||
self.cpp_info.components["isq-iec80000"].includedirs = ["include"]
|
||||
|
||||
self.cpp_info.components["systems"].requires = [
|
||||
"isq",
|
||||
"isq-natural",
|
||||
|
503
docs/conf.py
503
docs/conf.py
@@ -1,488 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
pygments.lexers.c_cpp
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Lexers for C/C++ languages.
|
||||
|
||||
:copyright: Copyright 2006-2019 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
from pygments.lexer import (
|
||||
RegexLexer,
|
||||
bygroups,
|
||||
default,
|
||||
include,
|
||||
inherit,
|
||||
this,
|
||||
using,
|
||||
words,
|
||||
)
|
||||
from pygments.token import (
|
||||
Comment,
|
||||
Error,
|
||||
Keyword,
|
||||
Name,
|
||||
Number,
|
||||
Operator,
|
||||
Punctuation,
|
||||
String,
|
||||
Text,
|
||||
)
|
||||
from pygments.util import get_bool_opt
|
||||
from sphinx.highlighting import lexers
|
||||
|
||||
|
||||
class MyCFamilyLexer(RegexLexer):
|
||||
#: optional Comment or Whitespace
|
||||
_ws = r"(?:\s|//.*?\n|/[*].*?[*]/)+"
|
||||
|
||||
# The trailing ?, rather than *, avoids a geometric performance drop here.
|
||||
#: only one /* */ style comment
|
||||
_ws1 = r"\s*(?:/[*].*?[*]/\s*)?"
|
||||
|
||||
tokens = {
|
||||
"whitespace": [
|
||||
# preprocessor directives: without whitespace
|
||||
(r"^#if\s+0", Comment.Preproc, "if0"),
|
||||
("^#", Comment.Preproc, "macro"),
|
||||
# or with whitespace
|
||||
(
|
||||
"^(" + _ws1 + r")(#if\s+0)",
|
||||
bygroups(using(this), Comment.Preproc),
|
||||
"if0",
|
||||
),
|
||||
("^(" + _ws1 + ")(#)", bygroups(using(this), Comment.Preproc), "macro"),
|
||||
(r"\n", Text),
|
||||
(r"\s+", Text),
|
||||
(r"\\\n", Text), # line continuation
|
||||
(r"//(\n|[\w\W]*?[^\\]\n)", Comment.Single),
|
||||
(r"/(\\\n)?[*][\w\W]*?[*](\\\n)?/", Comment.Multiline),
|
||||
# Open until EOF, so no ending delimeter
|
||||
(r"/(\\\n)?[*][\w\W]*", Comment.Multiline),
|
||||
],
|
||||
"statements": [
|
||||
(r'(L?)(")', bygroups(String.Affix, String), "string"),
|
||||
(
|
||||
r"(L?)(')(\\.|\\[0-7]{1,3}|\\x[a-fA-F0-9]{1,2}|[^\\\'\n])(')",
|
||||
bygroups(String.Affix, String.Char, String.Char, String.Char),
|
||||
),
|
||||
(r"\*/", Error),
|
||||
(r"[~!%^&*+=|?:<>/-]", Operator),
|
||||
(r"[()\[\],.]", Punctuation),
|
||||
(
|
||||
words(
|
||||
(
|
||||
"asm",
|
||||
"auto",
|
||||
"break",
|
||||
"case",
|
||||
"const",
|
||||
"continue",
|
||||
"default",
|
||||
"do",
|
||||
"else",
|
||||
"enum",
|
||||
"extern",
|
||||
"for",
|
||||
"goto",
|
||||
"if",
|
||||
"register",
|
||||
"restricted",
|
||||
"return",
|
||||
"sizeof",
|
||||
"static",
|
||||
"struct",
|
||||
"switch",
|
||||
"typedef",
|
||||
"union",
|
||||
"volatile",
|
||||
"while",
|
||||
),
|
||||
suffix=r"\b",
|
||||
),
|
||||
Keyword,
|
||||
),
|
||||
(
|
||||
r"(bool|int|long|float|short|double|char|unsigned|signed|void)\b",
|
||||
Keyword.Type,
|
||||
),
|
||||
(
|
||||
words(
|
||||
(
|
||||
"inline",
|
||||
"_inline",
|
||||
"__inline",
|
||||
"naked",
|
||||
"restrict",
|
||||
"thread",
|
||||
"typename",
|
||||
),
|
||||
suffix=r"\b",
|
||||
),
|
||||
Keyword.Reserved,
|
||||
),
|
||||
# Vector intrinsics
|
||||
(r"(__m(128i|128d|128|64))\b", Keyword.Reserved),
|
||||
# Microsoft-isms
|
||||
(
|
||||
words(
|
||||
(
|
||||
"asm",
|
||||
"int8",
|
||||
"based",
|
||||
"except",
|
||||
"int16",
|
||||
"stdcall",
|
||||
"cdecl",
|
||||
"fastcall",
|
||||
"int32",
|
||||
"declspec",
|
||||
"finally",
|
||||
"int64",
|
||||
"try",
|
||||
"leave",
|
||||
"wchar_t",
|
||||
"w64",
|
||||
"unaligned",
|
||||
"raise",
|
||||
"noop",
|
||||
"identifier",
|
||||
"forceinline",
|
||||
"assume",
|
||||
),
|
||||
prefix=r"__",
|
||||
suffix=r"\b",
|
||||
),
|
||||
Keyword.Reserved,
|
||||
),
|
||||
(r"(true|false|NULL)\b", Name.Builtin),
|
||||
(r"([a-zA-Z_]\w*)(\s*)(:)(?!:)", bygroups(Name.Label, Text, Punctuation)),
|
||||
(r"[a-zA-Z_]\w*", Name),
|
||||
],
|
||||
"root": [
|
||||
include("whitespace"),
|
||||
# functions
|
||||
(
|
||||
r"((?:[\w*\s])+?(?:\s|[*]))" # return arguments
|
||||
r"([a-zA-Z_]\w*)" # method name
|
||||
r"(\s*\([^;]*?\))" # signature
|
||||
r"([^;{]*)(\{)",
|
||||
bygroups(
|
||||
using(this), Name.Function, using(this), using(this), Punctuation
|
||||
),
|
||||
"function",
|
||||
),
|
||||
# function declarations
|
||||
(
|
||||
r"((?:[\w*\s])+?(?:\s|[*]))" # return arguments
|
||||
r"([a-zA-Z_]\w*)" # method name
|
||||
r"(\s*\([^;]*?\))" # signature
|
||||
r"([^;]*)(;)",
|
||||
bygroups(
|
||||
using(this), Name.Function, using(this), using(this), Punctuation
|
||||
),
|
||||
),
|
||||
default("statement"),
|
||||
],
|
||||
"statement": [
|
||||
include("whitespace"),
|
||||
include("statements"),
|
||||
("[{}]", Punctuation),
|
||||
(";", Punctuation, "#pop"),
|
||||
],
|
||||
"function": [
|
||||
include("whitespace"),
|
||||
include("statements"),
|
||||
(";", Punctuation),
|
||||
(r"\{", Punctuation, "#push"),
|
||||
(r"\}", Punctuation, "#pop"),
|
||||
],
|
||||
"string": [
|
||||
(r'"', String, "#pop"),
|
||||
(
|
||||
r'\\([\\abfnrtv"\']|x[a-fA-F0-9]{2,4}|'
|
||||
r"u[a-fA-F0-9]{4}|U[a-fA-F0-9]{8}|[0-7]{1,3})",
|
||||
String.Escape,
|
||||
),
|
||||
(r'[^\\"\n]+', String), # all other characters
|
||||
(r"\\\n", String), # line continuation
|
||||
(r"\\", String), # stray backslash
|
||||
],
|
||||
"macro": [
|
||||
(
|
||||
r"(include)(" + _ws1 + r")([^\n]+)",
|
||||
bygroups(Comment.Preproc, Text, Comment.PreprocFile),
|
||||
),
|
||||
(r"[^/\n]+", Comment.Preproc),
|
||||
(r"/[*](.|\n)*?[*]/", Comment.Multiline),
|
||||
(r"//.*?\n", Comment.Single, "#pop"),
|
||||
(r"/", Comment.Preproc),
|
||||
(r"(?<=\\)\n", Comment.Preproc),
|
||||
(r"\n", Comment.Preproc, "#pop"),
|
||||
],
|
||||
"if0": [
|
||||
(r"^\s*#if.*?(?<!\\)\n", Comment.Preproc, "#push"),
|
||||
(r"^\s*#el(?:se|if).*\n", Comment.Preproc, "#pop"),
|
||||
(r"^\s*#endif.*?(?<!\\)\n", Comment.Preproc, "#pop"),
|
||||
(r".*?\n", Comment),
|
||||
],
|
||||
}
|
||||
|
||||
stdlib_types = {
|
||||
"size_t",
|
||||
"ssize_t",
|
||||
"off_t",
|
||||
"wchar_t",
|
||||
"ptrdiff_t",
|
||||
"sig_atomic_t",
|
||||
"fpos_t",
|
||||
"clock_t",
|
||||
"time_t",
|
||||
"va_list",
|
||||
"jmp_buf",
|
||||
"FILE",
|
||||
"DIR",
|
||||
"div_t",
|
||||
"ldiv_t",
|
||||
"mbstate_t",
|
||||
"wctrans_t",
|
||||
"wint_t",
|
||||
"wctype_t",
|
||||
}
|
||||
c99_types = {
|
||||
"_Bool",
|
||||
"_Complex",
|
||||
"int8_t",
|
||||
"int16_t",
|
||||
"int32_t",
|
||||
"int64_t",
|
||||
"uint8_t",
|
||||
"uint16_t",
|
||||
"uint32_t",
|
||||
"uint64_t",
|
||||
"int_least8_t",
|
||||
"int_least16_t",
|
||||
"int_least32_t",
|
||||
"int_least64_t",
|
||||
"uint_least8_t",
|
||||
"uint_least16_t",
|
||||
"uint_least32_t",
|
||||
"uint_least64_t",
|
||||
"int_fast8_t",
|
||||
"int_fast16_t",
|
||||
"int_fast32_t",
|
||||
"int_fast64_t",
|
||||
"uint_fast8_t",
|
||||
"uint_fast16_t",
|
||||
"uint_fast32_t",
|
||||
"uint_fast64_t",
|
||||
"intptr_t",
|
||||
"uintptr_t",
|
||||
"intmax_t",
|
||||
"uintmax_t",
|
||||
}
|
||||
linux_types = {
|
||||
"clockid_t",
|
||||
"cpu_set_t",
|
||||
"cpumask_t",
|
||||
"dev_t",
|
||||
"gid_t",
|
||||
"id_t",
|
||||
"ino_t",
|
||||
"key_t",
|
||||
"mode_t",
|
||||
"nfds_t",
|
||||
"pid_t",
|
||||
"rlim_t",
|
||||
"sig_t",
|
||||
"sighandler_t",
|
||||
"siginfo_t",
|
||||
"sigset_t",
|
||||
"sigval_t",
|
||||
"socklen_t",
|
||||
"timer_t",
|
||||
"uid_t",
|
||||
}
|
||||
|
||||
def __init__(self, **options):
|
||||
self.stdlibhighlighting = get_bool_opt(options, "stdlibhighlighting", True)
|
||||
self.c99highlighting = get_bool_opt(options, "c99highlighting", True)
|
||||
self.platformhighlighting = get_bool_opt(options, "platformhighlighting", True)
|
||||
RegexLexer.__init__(self, **options)
|
||||
|
||||
def get_tokens_unprocessed(self, text):
|
||||
for index, token, value in RegexLexer.get_tokens_unprocessed(self, text):
|
||||
if token is Name:
|
||||
if self.stdlibhighlighting and value in self.stdlib_types:
|
||||
token = Keyword.Type
|
||||
elif self.c99highlighting and value in self.c99_types:
|
||||
token = Keyword.Type
|
||||
elif self.platformhighlighting and value in self.linux_types:
|
||||
token = Keyword.Type
|
||||
yield index, token, value
|
||||
|
||||
|
||||
class MyCppLexer(MyCFamilyLexer):
|
||||
"""
|
||||
For C++ source code with preprocessor directives.
|
||||
"""
|
||||
|
||||
name = "My C++"
|
||||
aliases = ["cpp", "c++"]
|
||||
filenames = [
|
||||
"*.cpp",
|
||||
"*.hpp",
|
||||
"*.c++",
|
||||
"*.h++",
|
||||
"*.cc",
|
||||
"*.hh",
|
||||
"*.cxx",
|
||||
"*.hxx",
|
||||
"*.C",
|
||||
"*.H",
|
||||
"*.cp",
|
||||
"*.CPP",
|
||||
]
|
||||
mimetypes = ["text/x-c++hdr", "text/x-c++src"]
|
||||
priority = 0.1
|
||||
|
||||
tokens = {
|
||||
"statements": [
|
||||
(
|
||||
words(
|
||||
(
|
||||
"catch",
|
||||
"const_cast",
|
||||
"delete",
|
||||
"dynamic_cast",
|
||||
"explicit",
|
||||
"export",
|
||||
"friend",
|
||||
"mutable",
|
||||
"namespace",
|
||||
"new",
|
||||
"operator",
|
||||
"private",
|
||||
"protected",
|
||||
"public",
|
||||
"reinterpret_cast",
|
||||
"restrict",
|
||||
"static_cast",
|
||||
"template",
|
||||
"this",
|
||||
"throw",
|
||||
"throws",
|
||||
"try",
|
||||
"typeid",
|
||||
"typename",
|
||||
"using",
|
||||
"virtual",
|
||||
"constexpr",
|
||||
"nullptr",
|
||||
"decltype",
|
||||
"thread_local",
|
||||
"alignas",
|
||||
"alignof",
|
||||
"static_assert",
|
||||
"noexcept",
|
||||
"override",
|
||||
"final",
|
||||
"constinit",
|
||||
"consteval",
|
||||
"constinit",
|
||||
"concept",
|
||||
"co_await",
|
||||
"co_return",
|
||||
"co_yield",
|
||||
"requires",
|
||||
"import",
|
||||
"module",
|
||||
),
|
||||
suffix=r"\b",
|
||||
),
|
||||
Keyword,
|
||||
),
|
||||
(r"char(16_t|32_t|8_t)\b", Keyword.Type),
|
||||
(r"(class)(\s+)", bygroups(Keyword, Text), "classname"),
|
||||
# C++11 raw strings
|
||||
(
|
||||
r'(R)(")([^\\()\s]{,16})(\()((?:.|\n)*?)(\)\3)(")',
|
||||
bygroups(
|
||||
String.Affix,
|
||||
String,
|
||||
String.Delimiter,
|
||||
String.Delimiter,
|
||||
String,
|
||||
String.Delimiter,
|
||||
String,
|
||||
),
|
||||
),
|
||||
# C++11 UTF-8/16/32 strings
|
||||
(r'(u8|u|U)(")', bygroups(String.Affix, String), "string"),
|
||||
# C++14 number separators
|
||||
(
|
||||
r"(\d[\d\']*\.[\d\']*|\.\d[\d\']*|\d[\d\']*)[eE][+-]?\d[\d\']*[LlUu]*",
|
||||
Number.Float,
|
||||
),
|
||||
(r"(\d[\d\']*\.[\d\']*|\.\d[\d\']*|\d[\d\']*[fF])[fF]?", Number.Float),
|
||||
(r"0x[0-9a-fA-F\']+[LlUu]*", Number.Hex),
|
||||
(r"0[0-7\']+[LlUu]*", Number.Oct),
|
||||
(r"\d[\d\']*[LlUu]*", Number.Integer),
|
||||
inherit,
|
||||
],
|
||||
"root": [
|
||||
inherit,
|
||||
# C++ Microsoft-isms
|
||||
(
|
||||
words(
|
||||
(
|
||||
"virtual_inheritance",
|
||||
"uuidof",
|
||||
"super",
|
||||
"single_inheritance",
|
||||
"multiple_inheritance",
|
||||
"interface",
|
||||
"event",
|
||||
),
|
||||
prefix=r"__",
|
||||
suffix=r"\b",
|
||||
),
|
||||
Keyword.Reserved,
|
||||
),
|
||||
# Offload C++ extensions, http://offload.codeplay.com/
|
||||
(r"__(offload|blockingoffload|outer)\b", Keyword.Pseudo),
|
||||
],
|
||||
"classname": [
|
||||
(r"[a-zA-Z_]\w*", Name.Class, "#pop"),
|
||||
# template specification
|
||||
(r"\s*(?=>)", Text, "#pop"),
|
||||
],
|
||||
}
|
||||
|
||||
def analyse_text(text):
|
||||
if re.search("#include <[a-z_]+>", text):
|
||||
return 0.2
|
||||
if re.search("using namespace ", text):
|
||||
return 0.4
|
||||
|
||||
|
||||
lexers["cpp"] = MyCppLexer(startinline=True)
|
||||
|
||||
# TODO Remove the above when Pygments release with fixes is available
|
||||
|
||||
|
||||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# This file only contains a selection of the most common options.
|
||||
# For a full list see the documentation:
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||
|
||||
import re
|
||||
|
||||
|
||||
def get_version():
|
||||
try:
|
||||
@@ -598,29 +121,9 @@ html_css_files = ["css/custom.css"]
|
||||
# -- Breathe configuration ---------------------------------------------------
|
||||
|
||||
|
||||
def configureDoxyfile(input_dir, output_dir):
|
||||
with open("Doxyfile.in", "r") as file:
|
||||
filedata = file.read()
|
||||
|
||||
filedata = filedata.replace("@DOXYGEN_INPUT_DIR@", input_dir)
|
||||
filedata = filedata.replace("@DOXYGEN_OUTPUT_DIR@", output_dir)
|
||||
|
||||
with open("Doxyfile", "w") as file:
|
||||
file.write(filedata)
|
||||
|
||||
|
||||
# Check if we're running on Read the Docs' servers
|
||||
read_the_docs_build = os.environ.get("READTHEDOCS", None) == "True"
|
||||
|
||||
# This should be a dictionary in which the keys are project names and the values
|
||||
# are paths to the folder containing the doxygen output for that project.
|
||||
breathe_projects = {}
|
||||
if read_the_docs_build:
|
||||
input_dir = "../src"
|
||||
output_dir = "build"
|
||||
configureDoxyfile(input_dir, output_dir)
|
||||
subprocess.call("doxygen", shell=True)
|
||||
breathe_projects["mp-units"] = output_dir + "/xml"
|
||||
breathe_projects = {"mp-units": "build/xml"}
|
||||
|
||||
# This should match one of the keys in the breathe_projects dictionary and
|
||||
# indicates which project should be used when the project is not specified on
|
||||
|
@@ -188,9 +188,6 @@ and define units like::
|
||||
struct electronvolt : named_scaled_unit<electronvolt, "eV", prefix,
|
||||
ratio(1'602'176'634, 1'000'000'000, -19), joule> {};
|
||||
|
||||
..
|
||||
TODO Submit a bug for above lexing problem
|
||||
|
||||
Finally, the last of the `named_scaled_unit` class template parameters
|
||||
provide a reference unit for scaling. Please note that it can be a dimension's
|
||||
base/coherent unit (like ``si::second``) or any other unit (i.e. ``si::minute``,
|
||||
|
@@ -45,6 +45,11 @@ Concepts
|
||||
A concept matching all unit types that have an atomic text symbol that can be used to aggregate it with
|
||||
other named units to form a final symbol of a derived unit.
|
||||
|
||||
.. concept:: template<typename T> AliasUnit
|
||||
|
||||
A concept matching all alias unit types in the library. Satisfied by all unit types derived
|
||||
from the instantiation of :class:`alias_unit`.
|
||||
|
||||
.. concept:: template<typename U, typename D> UnitOf
|
||||
|
||||
A concept matching only units of a specified dimension. Satisfied by all unit types that
|
||||
@@ -63,6 +68,11 @@ Concepts
|
||||
A concept matching all quantity-like types other than specialization of :class:`quantity`. Satisfied by
|
||||
all types for which a correct specialization of :class:`quantity_like_traits` type trait is provided.
|
||||
|
||||
.. concept:: template<typename T> QuantityPointLike
|
||||
|
||||
A concept matching all quantity-point-like types other than specialization of :class:`quantity_point`.
|
||||
Satisfied by all types for which a correct specialization of :class:`quantity_point_like_traits` type trait is provided.
|
||||
|
||||
.. concept:: template<typename T> WrappedQuantity
|
||||
|
||||
A concept matching types that wrap quantity objects. Satisfied by all wrapper types that
|
||||
|
185
docs/usage.rst
185
docs/usage.rst
@@ -22,8 +22,8 @@ This repository contains three independent CMake-based projects:
|
||||
- when this library will become part of the C++ standard it will have no external dependencies
|
||||
but until then it depends on:
|
||||
|
||||
- `{fmt} <https://github.com/fmtlib/fmt>`_ to provide text formatting of quantities.
|
||||
- `gsl-lite <https://github.com/gsl-lite/gsl-lite>`_ to verify runtime contracts with the ``gsl_Expects`` macro.
|
||||
- [for compilers other than VS2022] `{fmt} <https://github.com/fmtlib/fmt>`_ to provide text formatting of quantities.
|
||||
- [only for clang < 14 with libc++] `range-v3 <https://github.com/ericniebler/range-v3>`_ to provide needed C++20 concepts and utilities.
|
||||
|
||||
- *.*
|
||||
@@ -36,9 +36,13 @@ This repository contains three independent CMake-based projects:
|
||||
- `linear algebra <https://github.com/BobSteagall/wg21/tree/master/include>`_
|
||||
library based on proposal `P1385 <https://wg21.link/P1385>`_ used in some examples
|
||||
and tests.
|
||||
|
||||
- in case you also want to build the project's documentation you will need:
|
||||
|
||||
- `Doxygen <http://www.doxygen.nl>`_ to extract C++ entities information from the source
|
||||
code.
|
||||
- `Sphinx <https://www.sphinx-doc.org>`_ to build the documentation.
|
||||
- `Sphinx ReadTheDocs Theme <https://sphinx-rtd-theme.readthedocs.io/>`_
|
||||
- `Sphinx recommonmark <https://recommonmark.readthedocs.io>`_.
|
||||
- `Breathe <https://breathe.readthedocs.io/>`_ as a bridge between the Sphinx and Doxygen
|
||||
documentation systems.
|
||||
@@ -82,47 +86,47 @@ in *~/.conan/profiles* directory. An example profile can look as follows:
|
||||
arch=x86_64
|
||||
arch_build=x86_64
|
||||
compiler=gcc
|
||||
compiler.version=10
|
||||
compiler.version=12
|
||||
compiler.cppstd=20
|
||||
compiler.libcxx=libstdc++11
|
||||
build_type=Release
|
||||
|
||||
[options]
|
||||
[build_requires]
|
||||
|
||||
[conf]
|
||||
tools.cmake.cmaketoolchain:generator=Ninja
|
||||
|
||||
[env]
|
||||
CC=/usr/bin/gcc-10
|
||||
CXX=/usr/bin/g++-10
|
||||
CC=/usr/bin/gcc-12
|
||||
CXX=/usr/bin/g++-12
|
||||
|
||||
.. tip::
|
||||
|
||||
Please note that **mp-units** library requires C++20 to be set either in a Conan profile or forced
|
||||
via Conan command line. If you do the former, you will not need to provide ``-s compiler.cppstd=20``
|
||||
every time your run a Conan command line (as it is suggested below).
|
||||
every time your run a Conan command line (as provided in the command line instructions below).
|
||||
|
||||
Additionally, it is recommended to set Ninja as a CMake generator for Conan. To do so you should create
|
||||
a *~/.conan/global.conf* file that will set ``tools.cmake.cmaketoolchain:generator`` to one of Ninja
|
||||
generators. For example:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
tools.cmake.cmaketoolchain:generator="Ninja Multi-Config"
|
||||
|
||||
.. note::
|
||||
|
||||
*~/.conan/global.conf* file may also set ``tools.cmake.cmake_layout:build_folder_vars``` which
|
||||
`makes working with several compilers or build configurations easier
|
||||
<https://docs.conan.io/en/latest/reference/conanfile/tools/cmake/cmake_layout.html#multi-setting-option-cmake-layout>`_.
|
||||
For example the below line will force Conan to generate separate CMake presets and folders for each compiler:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
tools.cmake.cmake_layout:build_folder_vars=["settings.compiler", "settings.compiler.version"]
|
||||
|
||||
In such a case you will need to use a configuration specific preset name in the Conan instructions provided below
|
||||
rather then just ``default`` and ``release`` (i.e. ``gcc-11`` and ``gcc-11-release``)
|
||||
|
||||
|
||||
Build Options
|
||||
-------------
|
||||
|
||||
Environment Variables
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
CONAN_RUN_TESTS
|
||||
+++++++++++++++
|
||||
|
||||
**Values**: ``True``/``False``
|
||||
|
||||
**Defaulted to**: ``False``
|
||||
|
||||
Enables compilation of all the source code (tests and examples) and building the documentation.
|
||||
To support this it requires some additional Conan build dependencies described in
|
||||
`Repository Structure and Dependencies`_.
|
||||
It also runs unit tests during Conan build.
|
||||
|
||||
|
||||
Conan Options
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
@@ -139,15 +143,30 @@ Specifies how :ref:`design/downcasting:The Downcasting Facility` works:
|
||||
- ``on`` - downcasting always forced -> compile-time errors in case of duplicated definitions
|
||||
- ``automatic`` - downcasting automatically enabled if no collisions are present
|
||||
|
||||
build_docs
|
||||
++++++++++
|
||||
Conan Configuration Properties
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
build_all
|
||||
+++++++++
|
||||
|
||||
**Values**: ``True``/``False``
|
||||
|
||||
**Defaulted to**: ``True``
|
||||
**Defaulted to**: ``False``
|
||||
|
||||
If enabled, Conan installs the documentation generation dependencies (i.e. doxygen).
|
||||
Additionally, enables project documentation generation when the project is being built by Conan.
|
||||
Enables compilation of all the source code (tests and examples) and generating the documentation.
|
||||
To support this it requires some additional Conan build dependencies described in
|
||||
`Repository Structure and Dependencies`_.
|
||||
It also runs unit tests during Conan build (unless ``tools.build:skip_test`` configuration property is set to ``True``)
|
||||
|
||||
skip_docs
|
||||
+++++++++
|
||||
|
||||
**Values**: ``True``/``False``
|
||||
|
||||
**Defaulted to**: ``False``
|
||||
|
||||
If `build_all`_ is enabled, among others, Conan installs the documentation generation dependencies (i.e. doxygen) and
|
||||
turns on the project documentation generation. Such behavior can be disabled with this option.
|
||||
|
||||
CMake Options
|
||||
^^^^^^^^^^^^^
|
||||
@@ -203,6 +222,21 @@ UNITS_USE_LIBFMT
|
||||
Enables usage of `{fmt} <https://github.com/fmtlib/fmt>`_ library instead of the C++20 Standard Library feature.
|
||||
|
||||
|
||||
CMake with Presets Support
|
||||
--------------------------
|
||||
|
||||
It is recommended to use at least CMake 3.23 to build this project as this version introduced a support
|
||||
for CMake Presets schema version 4 used now by Conan to generate presets files. All build instructions
|
||||
below assume that you have such a support. If not, your CMake invocations have to be replaced to something
|
||||
like:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
mkdir build && cd build
|
||||
cmake .. -G "Ninja Multi-Config" -DCMAKE_TOOLCHAIN_FILE=<path_to_generators_dir>/conan_toolchain.cmake
|
||||
cmake --build . --config Release
|
||||
|
||||
|
||||
Installation and Reuse
|
||||
----------------------
|
||||
|
||||
@@ -294,8 +328,8 @@ library release the following steps may be performed:
|
||||
|
||||
mkdir my_project/build && cd my_project/build
|
||||
conan install .. -pr <your_conan_profile> -s compiler.cppstd=20 -b=missing
|
||||
cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release
|
||||
cmake --build .
|
||||
cmake .. -G "Ninja Multi-Config" -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake
|
||||
cmake --build . --config Release
|
||||
|
||||
|
||||
Conan + CMake (Live At Head)
|
||||
@@ -329,6 +363,9 @@ differences:
|
||||
[requires]
|
||||
mp-units/0.8.0@mpusz/testing
|
||||
|
||||
[layout]
|
||||
cmake_layout
|
||||
|
||||
[generators]
|
||||
CMakeToolchain
|
||||
CMakeDeps
|
||||
@@ -343,10 +380,9 @@ differences:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
mkdir my_project/build && cd my_project/build
|
||||
conan install .. -pr <your_conan_profile> -s compiler.cppstd=20 -b=outdated -u
|
||||
cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release
|
||||
cmake --build .
|
||||
conan install . -pr <your_conan_profile> -s compiler.cppstd=20 -b=outdated -u
|
||||
cmake --preset default
|
||||
cmake --build --preset release
|
||||
|
||||
|
||||
Install
|
||||
@@ -358,43 +394,60 @@ to find it, it is enough to perform the following steps:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
mkdir units/build && cd units/build
|
||||
conan install .. -pr <your_conan_profile> -s compiler.cppstd=20 -b=missing
|
||||
cmake ../src -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release
|
||||
cmake --install . --prefix <install_dir>
|
||||
conan install . -pr <your_conan_profile> -s compiler.cppstd=20 -b=missing
|
||||
mv CMakeUserPresets.json src
|
||||
cd src
|
||||
cmake --preset default -DCMAKE_INSTALL_PREFIX=<your_installation_path>
|
||||
cmake --build --preset release --target install
|
||||
|
||||
|
||||
Contributing (or just building all the tests, examples, and documentation)
|
||||
--------------------------------------------------------------------------
|
||||
Contributing (or just building all the tests and examples)
|
||||
----------------------------------------------------------
|
||||
|
||||
In case you would like to build all the source code (with unit tests and examples) and documentation
|
||||
in **mp-units** repository, you should:
|
||||
In case you would like to build all the source code (with unit tests and examples) in **mp-units** repository,
|
||||
you should:
|
||||
|
||||
1. Add remotes of additional Conan dependencies.
|
||||
2. Use the *CMakeLists.txt* from the top-level directory.
|
||||
3. Obtain Python dependencies.
|
||||
4. Run Conan with `CONAN_RUN_TESTS`_ = ``True``.
|
||||
1. Use the *CMakeLists.txt* from the top-level directory.
|
||||
2. Run Conan with `build_all`_ = ``True``
|
||||
(use ``-o build_docs=False`` if you want to skip the documentation generation).
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
git clone https://github.com/mpusz/units.git && cd units
|
||||
conan install . -pr <your_conan_profile> -s compiler.cppstd=20 -c mp-units:user.build:all=True -c user.build:skip_docs=True -b outdated -u
|
||||
conan build .
|
||||
|
||||
The above will download and install all of the dependencies needed for the development of the library,
|
||||
build all of the source code and run unit tests.
|
||||
|
||||
If you prefer to build the project via CMake rather then Conan, then you should replace the last ``conan build .``
|
||||
step with the explicit CMake build:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
cmake --preset default
|
||||
cmake --build --preset release
|
||||
cmake --build --preset release --target test
|
||||
|
||||
|
||||
Building documentation
|
||||
----------------------
|
||||
|
||||
In case you would like to build the project's documentation, you should:
|
||||
|
||||
1. Use the *CMakeLists.txt* from the top-level directory.
|
||||
2. Obtain Python dependencies.
|
||||
3. Run Conan with `build_all`_ = ``True``.
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
git clone https://github.com/mpusz/units.git && cd units
|
||||
pip3 install -r docs/requirements.txt
|
||||
mkdir units/build && cd units/build
|
||||
conan install .. -pr <your_conan_profile> -s compiler.cppstd=20 -e mp-units:CONAN_RUN_TESTS=True -b outdated -u
|
||||
conan build ..
|
||||
conan install . -pr <your_conan_profile> -s compiler.cppstd=20 -c mp-units:user.build:all=True -b missing
|
||||
cmake --preset default
|
||||
cmake --build --preset release --target documentation
|
||||
|
||||
The above will download and install all of the dependencies needed for the development of the library,
|
||||
build all of the source code and documentation, and run unit tests.
|
||||
|
||||
If you prefer to build the project via CMake rather then Conan, then you should replace the last ``conan build ..``
|
||||
step with the CMake build:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
# ...
|
||||
cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release
|
||||
cmake --build .
|
||||
ctest
|
||||
The above will download and install all of the dependencies needed and build the documentation.
|
||||
|
||||
|
||||
Packaging
|
||||
@@ -404,7 +457,7 @@ To test CMake installation and Conan packaging or create a Conan package run:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
conan create . <username>/<channel> -pr <your_conan_profile> -s compiler.cppstd=20 -e mp-units:CONAN_RUN_TESTS=True -b outdated -u
|
||||
conan create . <username>/<channel> -pr <your_conan_profile> -s compiler.cppstd=20 -c mp-units:user.build:all=True -c user.build:skip_docs=True -b outdated -u
|
||||
|
||||
The above will create a Conan package and run tests provided in *./test_package* directory.
|
||||
|
||||
|
@@ -258,14 +258,14 @@ Even though the base dimension of ``si::fps`` is defined in terms of
|
||||
``si::metre`` foot is preserved as the base unit of length in both systems::
|
||||
|
||||
constexpr auto fps_yard = fps::length<fps::yard>(1.);
|
||||
constexpr auto fps_area = quantity_cast<unknown_coherent_unit>(fps_yard * fps_yard);
|
||||
constexpr auto fps_area = fps_yard * fps_yard;
|
||||
std::cout << fps_yard << "\n"; // 1 yd
|
||||
std::cout << fps_area << "\n"; // 9 ft²
|
||||
std::cout << quantity_cast<decltype(fps_area)::dimension::coherent_unit>(fps_area) << "\n"; // 9 ft²
|
||||
|
||||
constexpr auto si_fps_yard = si::fps::length<si::fps::yard>(1.);
|
||||
constexpr auto si_fps_area = quantity_cast<unknown_coherent_unit>(si_fps_yard * si_fps_yard);
|
||||
constexpr auto si_fps_area = si_fps_yard * si_fps_yard;
|
||||
std::cout << si_fps_yard << "\n"; // 1 yd
|
||||
std::cout << si_fps_area << "\n"; // 9 ft²
|
||||
std::cout << quantity_cast<decltype(si_fps_area)::dimension::coherent_unit>(si_fps_area) << "\n"; // 9 ft²
|
||||
|
||||
In most cases we want conversions between systems and that is why nearly all
|
||||
systems provided with this library are implemented in terms on the :term:`SI`
|
||||
|
@@ -59,7 +59,7 @@ It works just like `quantity_like_traits`, except that
|
||||
``number(T)`` is replaced with ``relative(T)`` that returns the `QuantityLike` value
|
||||
and ``dimension`` is replaced with ``origin``.
|
||||
|
||||
Similar to `quantity` and `quantity_kind`, `quantity_point` and `quantity_kind_point`
|
||||
Similar to `quantity` and `quantity_kind`, `quantity_point` and `quantity_point_kind`
|
||||
provide a deduction guide from `QuantityPointLike`::
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
@@ -52,7 +52,7 @@ dimensions used in the division operation:
|
||||
static_assert(std::is_same_v<decltype(result)::dimension,
|
||||
unknown_dimension<exponent<dim_length, 1>, exponent<dim_time, -1>>>);
|
||||
static_assert(std::is_same_v<decltype(result)::unit,
|
||||
scaled_unit<ratio(1, 36, 1), unknown_coherent_unit>>);
|
||||
scaled_unit<ratio(1, 36, 1), unknown_coherent_unit<exponent<dim_length, 1>, exponent<dim_time, -1>>>>>);
|
||||
|
||||
.. important::
|
||||
|
||||
@@ -81,7 +81,7 @@ this particular unknown derived dimension.
|
||||
In case we would like to print the result in terms of base units we can simply do the
|
||||
following::
|
||||
|
||||
auto s = quantity_cast<unknown_coherent_unit>(result);
|
||||
auto s = quantity_cast<decltype(result)::dimension::coherent_unit>(result);
|
||||
std::cout << "Speed: " << s << '\n'; // prints 'Speed: 20 m/s'
|
||||
|
||||
.. seealso::
|
||||
|
@@ -33,7 +33,7 @@ using namespace units;
|
||||
namespace fps {
|
||||
|
||||
struct foot : named_unit<foot, "ft"> {};
|
||||
struct yard : named_scaled_unit<yard, "yd", as_magnitude<3>(), foot> {};
|
||||
struct yard : named_scaled_unit<yard, "yd", mag<3>(), foot> {};
|
||||
|
||||
struct dim_length : base_dimension<"L", foot> {};
|
||||
|
||||
@@ -54,8 +54,8 @@ using length = quantity<dim_length, U, Rep>;
|
||||
|
||||
namespace fps {
|
||||
|
||||
struct foot : named_scaled_unit<foot, "ft", as_magnitude<ratio(3'048, 1'000, -1)>(), metre> {};
|
||||
struct yard : named_scaled_unit<yard, "yd", as_magnitude<3>(), foot> {};
|
||||
struct foot : named_scaled_unit<foot, "ft", mag<ratio{3'048, 10'000}>(), metre> {};
|
||||
struct yard : named_scaled_unit<yard, "yd", mag<3>(), foot> {};
|
||||
|
||||
struct dim_length : base_dimension<"L", foot> {};
|
||||
|
||||
@@ -84,20 +84,17 @@ void conversions()
|
||||
void unknown_dimensions()
|
||||
{
|
||||
constexpr auto fps_yard = fps::length<fps::yard>(1.);
|
||||
constexpr auto fps_area = quantity_cast<unknown_coherent_unit>(fps_yard * fps_yard);
|
||||
constexpr auto fps_area = fps_yard * fps_yard;
|
||||
std::cout << fps_yard << "\n";
|
||||
std::cout << fps_area << "\n";
|
||||
std::cout << quantity_cast<decltype(fps_area)::dimension::coherent_unit>(fps_area) << "\n";
|
||||
|
||||
constexpr auto si_fps_yard = si::fps::length<si::fps::yard>(1.);
|
||||
constexpr auto si_fps_area = quantity_cast<unknown_coherent_unit>(si_fps_yard * si_fps_yard);
|
||||
constexpr auto si_fps_area = si_fps_yard * si_fps_yard;
|
||||
std::cout << si_fps_yard << "\n";
|
||||
std::cout << si_fps_area << "\n";
|
||||
std::cout << quantity_cast<decltype(si_fps_area)::dimension::coherent_unit>(si_fps_area) << "\n";
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const ratio& r)
|
||||
{
|
||||
return os << "ratio{" << r.num << ", " << r.den << ", " << r.exp << "}";
|
||||
}
|
||||
std::ostream& operator<<(std::ostream& os, const ratio& r) { return os << "ratio{" << r.num << ", " << r.den << "}"; }
|
||||
|
||||
template<Unit U>
|
||||
std::ostream& operator<<(std::ostream& os, const U& u)
|
||||
|
@@ -157,9 +157,8 @@ public:
|
||||
using legs = std::vector<leg>;
|
||||
|
||||
template<std::ranges::input_range R>
|
||||
requires std::same_as<std::ranges::range_value_t<R>,
|
||||
waypoint> explicit task(const R& r) :
|
||||
waypoints_(std::ranges::begin(r), std::ranges::end(r))
|
||||
requires std::same_as<std::ranges::range_value_t<R>, waypoint>
|
||||
explicit task(const R& r) : waypoints_(std::ranges::begin(r), std::ranges::end(r))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -215,8 +214,7 @@ constexpr height agl(altitude glider_alt, altitude terrain_level) { return glide
|
||||
|
||||
inline units::isq::si::length<units::isq::si::kilometre> length_3d(distance dist, height h)
|
||||
{
|
||||
// TODO support for hypot(q, q)
|
||||
return sqrt(pow<2>(dist.common()) + pow<2>(h.common()));
|
||||
return hypot(dist.common(), h.common());
|
||||
}
|
||||
|
||||
distance glide_distance(const flight_point& pos, const glider& g, const task& t, const safety& s, altitude ground_alt);
|
||||
|
@@ -54,6 +54,7 @@ template<basic_fixed_string Symbol, NamedUnit U>
|
||||
struct base_dimension {
|
||||
static constexpr auto symbol = Symbol; ///< Unique base dimension identifier
|
||||
using base_unit = U; ///< Base unit adopted for this dimension
|
||||
static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto mag = magnitude{};
|
||||
};
|
||||
|
||||
// base_dimension_less
|
||||
|
@@ -42,7 +42,7 @@ namespace units::detail {
|
||||
template<typename... Es>
|
||||
constexpr Magnitude auto absolute_magnitude(exponent_list<Es...>)
|
||||
{
|
||||
return (pow<ratio{Es::num, Es::den}>(Es::dimension::base_unit::mag) * ... * magnitude<>{});
|
||||
return (magnitude<>{} * ... * pow<ratio{Es::num, Es::den}>(Es::dimension::base_unit::mag));
|
||||
}
|
||||
|
||||
} // namespace units::detail
|
@@ -29,6 +29,7 @@
|
||||
#include <units/bits/external/type_traits.h>
|
||||
#include <units/customization_points.h>
|
||||
#include <units/magnitude.h>
|
||||
#include <units/symbol_text.h>
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include <cstdint>
|
||||
@@ -86,6 +87,20 @@ inline constexpr bool is_named = false;
|
||||
template<typename T>
|
||||
concept NamedUnit = Unit<T> && detail::is_named<T>;
|
||||
|
||||
template<Unit U, basic_symbol_text Symbol>
|
||||
struct alias_unit;
|
||||
|
||||
// TODO: Remove when P1985 accepted
|
||||
namespace detail {
|
||||
|
||||
template<Unit U, basic_symbol_text Symbol>
|
||||
void to_base_alias_unit(const volatile alias_unit<U, Symbol>*);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T>
|
||||
concept AliasUnit = requires(T* t) { detail::to_base_alias_unit(t); };
|
||||
|
||||
// BaseDimension
|
||||
template<basic_fixed_string Symbol, NamedUnit U>
|
||||
struct base_dimension;
|
||||
|
@@ -66,15 +66,13 @@ struct common_quantity_reference_impl<reference<D1, U1>, reference<D2, U2>> {
|
||||
|
||||
template<typename D1, typename U1, typename D2, typename U2>
|
||||
struct common_quantity_reference_impl<reference<D1, U1>, reference<D2, U2>> {
|
||||
static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto mag = common_magnitude(reference<D1, U1>::mag,
|
||||
reference<D2, U2>::mag);
|
||||
using dimension = conditional<is_specialization_of<D1, unknown_dimension>, D2, D1>;
|
||||
static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto m1 = D1::base_units_ratio * U1::mag;
|
||||
static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto m2 = D2::base_units_ratio * U2::mag;
|
||||
static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto cm = common_magnitude(m1, m2);
|
||||
using unit = downcast_unit<dimension, cm / dimension::base_units_ratio>;
|
||||
using unit = downcast_unit<dimension, mag / dimension::mag>;
|
||||
using type = reference<dimension, unit>;
|
||||
};
|
||||
|
||||
|
||||
template<Quantity Q1, QuantityEquivalentTo<Q1> Q2>
|
||||
using common_quantity_reference =
|
||||
TYPENAME detail::common_quantity_reference_impl<std::remove_const_t<decltype(Q1::reference)>,
|
||||
|
@@ -39,8 +39,7 @@ inline constexpr bool compatible_units<exponent_list<Es...>, Us...> = (UnitOf<Us
|
||||
template<Unit... Us, typename... Es>
|
||||
constexpr Magnitude auto derived_mag(exponent_list<Es...>)
|
||||
{
|
||||
return (as_magnitude<1>() * ... *
|
||||
pow<ratio{Es::num, Es::den}>(Us::mag / dimension_unit<typename Es::dimension>::mag));
|
||||
return (magnitude<>{} * ... * pow<ratio{Es::num, Es::den}>(Us::mag / dimension_unit<typename Es::dimension>::mag));
|
||||
}
|
||||
|
||||
template<DerivedDimension D, Unit... Us>
|
||||
|
@@ -37,12 +37,12 @@ namespace units {
|
||||
*
|
||||
* Sometimes a temporary partial result of a complex calculation may not result in a predefined
|
||||
* dimension. In such a case an `unknown_dimension` is created with a coherent unit of `unknown_coherent_unit`
|
||||
* and ratio(1).
|
||||
* with a magnitude being the absolute one of all the exponents of such a dimension.
|
||||
*
|
||||
* @tparam Es the list of exponents of ingredient dimensions
|
||||
*/
|
||||
template<Exponent... Es>
|
||||
struct unknown_dimension : derived_dimension<unknown_dimension<Es...>, unknown_coherent_unit, Es...> {};
|
||||
struct unknown_dimension : derived_dimension<unknown_dimension<Es...>, unknown_coherent_unit<Es...>, Es...> {};
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
@@ -23,6 +23,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <units/bits/basic_concepts.h>
|
||||
#include <units/reference.h>
|
||||
#include <units/unit.h>
|
||||
|
||||
namespace units {
|
||||
@@ -72,8 +73,7 @@ struct equivalent_impl<D1, D2> :
|
||||
// additionally accounts for unknown dimensions
|
||||
template<Unit U1, Dimension D1, Unit U2, Dimension D2>
|
||||
struct equivalent_unit :
|
||||
std::disjunction<equivalent_impl<U1, U2>,
|
||||
std::bool_constant<U1::mag / dimension_unit<D1>::mag == U2::mag / dimension_unit<D2>::mag>> {};
|
||||
std::disjunction<equivalent_impl<U1, U2>, std::bool_constant<reference<D1, U1>::mag == reference<D2, U2>::mag>> {};
|
||||
|
||||
// point origins
|
||||
|
||||
|
@@ -37,8 +37,9 @@ inline constexpr bool same_exponents_of = false;
|
||||
|
||||
template<Exponent... Es, template<typename...> typename DimTemplate>
|
||||
inline constexpr bool same_exponents_of<unknown_dimension<Es...>, DimTemplate> =
|
||||
requires { typename DimTemplate<unknown_dimension<Es...>, unknown_coherent_unit, typename Es::dimension...>; } &&
|
||||
std::same_as<exponent_list<Es...>, typename DimTemplate<unknown_dimension<Es...>, unknown_coherent_unit,
|
||||
requires {
|
||||
typename DimTemplate<unknown_dimension<Es...>, unknown_coherent_unit<Es...>, typename Es::dimension...>;
|
||||
}&& std::same_as<exponent_list<Es...>, typename DimTemplate<unknown_dimension<Es...>, unknown_coherent_unit<Es...>,
|
||||
typename Es::dimension...>::recipe>;
|
||||
|
||||
} // namespace detail
|
||||
|
@@ -39,108 +39,20 @@ template<typename T>
|
||||
return v < 0 ? -v : v;
|
||||
}
|
||||
|
||||
// the following functions enable gcd and related computations on ratios
|
||||
// with exponents. They avoid overflow. Further information here:
|
||||
// https://github.com/mpusz/units/issues/62#issuecomment-588152833
|
||||
|
||||
// Computes (a * b) mod m relies on unsigned integer arithmetic, should not
|
||||
// overflow
|
||||
[[nodiscard]] constexpr std::uint64_t mulmod(std::uint64_t a, std::uint64_t b, std::uint64_t m)
|
||||
{
|
||||
std::uint64_t res = 0;
|
||||
|
||||
if (b >= m) {
|
||||
if (m > UINT64_MAX / 2u) {
|
||||
b -= m;
|
||||
} else {
|
||||
b %= m;
|
||||
}
|
||||
}
|
||||
|
||||
while (a != 0) {
|
||||
if (a & 1) {
|
||||
if (b >= m - res) {
|
||||
res -= m;
|
||||
}
|
||||
res += b;
|
||||
}
|
||||
a >>= 1;
|
||||
|
||||
std::uint64_t temp_b = b;
|
||||
if (b >= m - b) {
|
||||
temp_b -= m;
|
||||
}
|
||||
b += temp_b;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// Calculates (a ^ e) mod m , should not overflow.
|
||||
[[nodiscard]] constexpr std::uint64_t modpow(std::uint64_t a, std::uint64_t e, std::uint64_t m)
|
||||
{
|
||||
a %= m;
|
||||
std::uint64_t result = 1;
|
||||
|
||||
while (e > 0) {
|
||||
if (e & 1) {
|
||||
result = mulmod(result, a, m);
|
||||
}
|
||||
a = mulmod(a, a, m);
|
||||
e >>= 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// gcd(a * 10 ^ e, b), should not overflow
|
||||
[[nodiscard]] constexpr std::intmax_t gcdpow(std::intmax_t a, std::intmax_t e, std::intmax_t b) noexcept
|
||||
{
|
||||
assert(a > 0);
|
||||
assert(e >= 0);
|
||||
assert(b > 0);
|
||||
|
||||
// gcd(i, j) = gcd(j, i mod j) for j != 0 Euclid;
|
||||
//
|
||||
// gcd(a 10^e, b) = gcd(b, a 10^e mod b)
|
||||
//
|
||||
// (a 10^e) mod b -> [ (a mod b) (10^e mod b) ] mod b
|
||||
|
||||
return std::gcd(
|
||||
b, static_cast<std::intmax_t>(mulmod(static_cast<std::uint64_t>(a % b),
|
||||
modpow(10, static_cast<std::uint64_t>(e), static_cast<std::uint64_t>(b)),
|
||||
static_cast<std::uint64_t>(b))));
|
||||
}
|
||||
|
||||
constexpr void cwap(std::intmax_t& lhs, std::intmax_t& rhs)
|
||||
{
|
||||
std::intmax_t tmp = lhs;
|
||||
lhs = rhs;
|
||||
rhs = tmp;
|
||||
}
|
||||
|
||||
// Computes the rational gcd of n1/d1 x 10^e1 and n2/d2 x 10^e2
|
||||
[[nodiscard]] constexpr auto gcd_frac(std::intmax_t n1, std::intmax_t d1, std::intmax_t e1, std::intmax_t n2,
|
||||
std::intmax_t d2, std::intmax_t e2) noexcept
|
||||
// Computes the rational gcd of n1/d1 and n2/d2
|
||||
[[nodiscard]] constexpr auto gcd_frac(std::intmax_t n1, std::intmax_t d1, std::intmax_t n2, std::intmax_t d2) noexcept
|
||||
{
|
||||
// Short cut for equal ratios
|
||||
if (n1 == n2 && d1 == d2 && e1 == e2) {
|
||||
return std::array{n1, d1, e1};
|
||||
if (n1 == n2 && d1 == d2) {
|
||||
return std::array{n1, d1};
|
||||
}
|
||||
|
||||
if (e2 > e1) {
|
||||
detail::cwap(n1, n2);
|
||||
detail::cwap(d1, d2);
|
||||
detail::cwap(e1, e2);
|
||||
}
|
||||
|
||||
std::intmax_t exp = e2; // minimum
|
||||
|
||||
// gcd(a/b,c/d) = gcd(a⋅d, c⋅b) / b⋅d
|
||||
|
||||
assert(std::numeric_limits<std::intmax_t>::max() / n1 > d2);
|
||||
assert(std::numeric_limits<std::intmax_t>::max() / n2 > d1);
|
||||
|
||||
std::intmax_t num = detail::gcdpow(n1 * d2, e1 - e2, n2 * d1);
|
||||
std::intmax_t num = std::gcd(n1 * d2, n2 * d1);
|
||||
|
||||
assert(std::numeric_limits<std::intmax_t>::max() / d1 > d2);
|
||||
|
||||
@@ -148,29 +60,19 @@ constexpr void cwap(std::intmax_t& lhs, std::intmax_t& rhs)
|
||||
|
||||
std::intmax_t gcd = std::gcd(num, den);
|
||||
|
||||
return std::array{num / gcd, den / gcd, exp};
|
||||
return std::array{num / gcd, den / gcd};
|
||||
}
|
||||
|
||||
constexpr void normalize(std::intmax_t& num, std::intmax_t& den, std::intmax_t& exp)
|
||||
constexpr void normalize(std::intmax_t& num, std::intmax_t& den)
|
||||
{
|
||||
if (num == 0) {
|
||||
den = 1;
|
||||
exp = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
std::intmax_t gcd = std::gcd(num, den);
|
||||
num = num * (den < 0 ? -1 : 1) / gcd;
|
||||
den = detail::abs(den) / gcd;
|
||||
|
||||
while (num % 10 == 0) {
|
||||
num /= 10;
|
||||
++exp;
|
||||
}
|
||||
while (den % 10 == 0) {
|
||||
den /= 10;
|
||||
--exp;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::intmax_t safe_multiply(std::intmax_t lhs, std::intmax_t rhs)
|
||||
|
@@ -37,7 +37,7 @@ constexpr auto magnitude_text()
|
||||
{
|
||||
constexpr auto exp10 = extract_power_of_10(M);
|
||||
|
||||
constexpr Magnitude auto base = M / pow<exp10>(as_magnitude<10>());
|
||||
constexpr Magnitude auto base = M / pow<exp10>(mag<10>());
|
||||
constexpr Magnitude auto num = numerator(base);
|
||||
constexpr Magnitude auto den = denominator(base);
|
||||
static_assert(base == num / den, "Printing rational powers, or irrational bases, not yet supported");
|
||||
@@ -72,7 +72,7 @@ constexpr auto magnitude_text()
|
||||
template<Unit U, Magnitude auto M, std::size_t SymbolLen>
|
||||
constexpr auto prefix_or_magnitude_text()
|
||||
{
|
||||
if constexpr (M == as_magnitude<1>()) {
|
||||
if constexpr (M == mag<1>()) {
|
||||
// no ratio/prefix
|
||||
return basic_fixed_string("");
|
||||
} else {
|
||||
|
@@ -34,7 +34,7 @@ namespace units {
|
||||
template<typename Rep, typename Period>
|
||||
struct quantity_like_traits<std::chrono::duration<Rep, Period>> {
|
||||
private:
|
||||
static constexpr auto mag = as_magnitude<ratio(Period::num, Period::den)>();
|
||||
static constexpr auto mag = ::units::mag<ratio(Period::num, Period::den)>();
|
||||
public:
|
||||
using dimension = isq::si::dim_time;
|
||||
using unit = downcast_unit<dimension, mag>;
|
||||
@@ -48,7 +48,7 @@ struct clock_origin : point_origin<isq::si::dim_time> {};
|
||||
template<typename C, typename Rep, typename Period>
|
||||
struct quantity_point_like_traits<std::chrono::time_point<C, std::chrono::duration<Rep, Period>>> {
|
||||
private:
|
||||
static constexpr auto mag = as_magnitude<ratio(Period::num, Period::den)>();
|
||||
static constexpr auto mag = ::units::mag<ratio(Period::num, Period::den)>();
|
||||
public:
|
||||
using origin = clock_origin<C>;
|
||||
using unit = downcast_unit<typename origin::dimension, mag>;
|
||||
@@ -75,12 +75,7 @@ constexpr std::intmax_t pow_10(std::intmax_t v)
|
||||
template<ratio R>
|
||||
constexpr auto to_std_ratio_impl()
|
||||
{
|
||||
if constexpr (R.exp == 0)
|
||||
return std::ratio<R.num, R.den>{};
|
||||
else if constexpr (R.exp > 0)
|
||||
return std::ratio<R.num * pow_10(R.exp), R.den>{};
|
||||
else
|
||||
return std::ratio<R.num, R.den * pow_10(-R.exp)>{};
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
@@ -23,7 +23,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <units/base_dimension.h>
|
||||
#include <units/bits/base_units_ratio.h>
|
||||
#include <units/bits/absolute_magnitude.h>
|
||||
#include <units/bits/derived_dimension_base.h>
|
||||
#include <units/bits/dim_consolidate.h>
|
||||
#include <units/bits/dim_unpack.h>
|
||||
@@ -72,8 +72,8 @@ using make_dimension = TYPENAME to_derived_dimension_base<
|
||||
* and in CGS barye. Those two units are not directly related with each other with some ratio. As they both are
|
||||
* coherent units of their dimensions, the ratio between them is directly determined by the ratios of base units
|
||||
* defined in base dimensions end their exponents in the derived dimension recipe. To provide interoperability of
|
||||
* such quantities of different systems base_units_ratio is being used. The result of the division of two
|
||||
* base_units_ratio of two quantities of equivalent dimensions in two different systems gives a ratio between their
|
||||
* such quantities of different systems mag is being used. The result of the division of two
|
||||
* mag of two quantities of equivalent dimensions in two different systems gives a ratio between their
|
||||
* coherent units. Alternatively, the user would always have to directly define a barye in terms of pascal or vice
|
||||
* versa.
|
||||
*
|
||||
@@ -85,8 +85,8 @@ template<typename Child, Unit U, Exponent... Es>
|
||||
struct derived_dimension : downcast_dispatch<Child, typename detail::make_dimension<Es...>> {
|
||||
using recipe = exponent_list<Es...>;
|
||||
using coherent_unit = U;
|
||||
static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto base_units_ratio =
|
||||
detail::absolute_magnitude(typename derived_dimension::exponents());
|
||||
static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto mag =
|
||||
detail::absolute_magnitude(typename derived_dimension::exponents()) / U::mag;
|
||||
};
|
||||
|
||||
} // namespace units
|
||||
|
@@ -31,7 +31,7 @@
|
||||
namespace units {
|
||||
|
||||
struct one : derived_unit<one> {};
|
||||
struct percent : named_scaled_unit<percent, "%", as_magnitude<ratio(1, 100)>(), one> {};
|
||||
struct percent : named_scaled_unit<percent, "%", mag<ratio(1, 100)>(), one> {};
|
||||
|
||||
/**
|
||||
* @brief Dimension one
|
||||
|
@@ -189,9 +189,6 @@ constexpr widen_t<T> compute_base_power(BasePower auto bp)
|
||||
if (bp.power.den != 1) {
|
||||
throw std::invalid_argument{"Rational powers not yet supported"};
|
||||
}
|
||||
if (bp.power.exp < 0) {
|
||||
throw std::invalid_argument{"Unsupported exp value"};
|
||||
}
|
||||
|
||||
if (bp.power.num < 0) {
|
||||
if constexpr (std::is_integral_v<T>) {
|
||||
@@ -201,7 +198,7 @@ constexpr widen_t<T> compute_base_power(BasePower auto bp)
|
||||
}
|
||||
}
|
||||
|
||||
auto power = numerator(bp.power);
|
||||
auto power = bp.power.num;
|
||||
return int_power(static_cast<widen_t<T>>(bp.get_base()), power);
|
||||
}
|
||||
|
||||
@@ -344,7 +341,7 @@ inline constexpr bool is_base_power_pack_valid = all_base_powers_valid<BPs...> &
|
||||
|
||||
constexpr bool is_rational(BasePower auto bp)
|
||||
{
|
||||
return std::is_integral_v<decltype(bp.get_base())> && (bp.power.den == 1) && (bp.power.exp >= 0);
|
||||
return std::is_integral_v<decltype(bp.get_base())> && (bp.power.den == 1);
|
||||
}
|
||||
|
||||
constexpr bool is_integral(BasePower auto bp) { return is_rational(bp) && bp.power.num > 0; }
|
||||
@@ -498,8 +495,8 @@ namespace detail {
|
||||
template<auto BP>
|
||||
constexpr auto integer_part(magnitude<BP>)
|
||||
{
|
||||
constexpr auto power_num = numerator(BP.power);
|
||||
constexpr auto power_den = denominator(BP.power);
|
||||
constexpr auto power_num = BP.power.num;
|
||||
constexpr auto power_den = BP.power.den;
|
||||
|
||||
if constexpr (std::is_integral_v<decltype(BP.get_base())> && (power_num >= power_den)) {
|
||||
constexpr auto largest_integer_power = [=](BasePower auto bp) {
|
||||
@@ -556,7 +553,7 @@ namespace detail {
|
||||
template<auto BP>
|
||||
constexpr auto remove_positive_power(magnitude<BP> m)
|
||||
{
|
||||
if constexpr (numerator(BP.power) < 0) {
|
||||
if constexpr (BP.power.num < 0) {
|
||||
return m;
|
||||
} else {
|
||||
return magnitude<>{};
|
||||
@@ -599,7 +596,7 @@ constexpr auto common_magnitude(magnitude<H1, T1...>, magnitude<H2, T2...>)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// `as_magnitude()` implementation.
|
||||
// `mag()` implementation.
|
||||
|
||||
// Sometimes we need to give the compiler a "shortcut" when factorizing large numbers (specifically, numbers whose
|
||||
// _first factor_ is very large). If we don't, we can run into limits on the number of constexpr steps or iterations.
|
||||
@@ -650,10 +647,19 @@ inline constexpr auto prime_factorization_v = prime_factorization<N>::value;
|
||||
*/
|
||||
template<ratio R>
|
||||
requires(R.num > 0)
|
||||
constexpr Magnitude auto as_magnitude()
|
||||
constexpr Magnitude auto mag()
|
||||
{
|
||||
return pow<ratio{R.exp}>(detail::prime_factorization_v<10>) * detail::prime_factorization_v<R.num> /
|
||||
detail::prime_factorization_v<R.den>;
|
||||
return detail::prime_factorization_v<R.num> / detail::prime_factorization_v<R.den>;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a Magnitude which is some rational number raised to a rational power.
|
||||
*/
|
||||
template<ratio Base, ratio Pow>
|
||||
requires(Base.num > 0)
|
||||
constexpr Magnitude auto mag_power()
|
||||
{
|
||||
return pow<Pow>(mag<Base>());
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
@@ -663,7 +669,7 @@ constexpr ratio get_power(T base, magnitude<BPs...>)
|
||||
return ((BPs.get_base() == base ? BPs.power : ratio{0}) + ... + ratio{0});
|
||||
}
|
||||
|
||||
constexpr std::intmax_t integer_part(ratio r) { return numerator(r) / denominator(r); }
|
||||
constexpr std::intmax_t integer_part(ratio r) { return r.num / r.den; }
|
||||
|
||||
constexpr std::intmax_t extract_power_of_10(Magnitude auto m)
|
||||
{
|
||||
|
@@ -301,4 +301,42 @@ template<Quantity To, std::same_as<typename To::dimension> D, typename U, std::s
|
||||
return ::units::round<typename To::unit>(q);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Computes the square root of the sum of the squares of x and y,
|
||||
* without undue overflow or underflow at intermediate stages of the computation
|
||||
*/
|
||||
template<Quantity Q1, Quantity Q2>
|
||||
[[nodiscard]] inline std::common_type_t<Q1, Q2> hypot(const Q1& x, const Q2& y) noexcept
|
||||
requires requires { typename std::common_type_t<Q1, Q2>; } &&
|
||||
requires(std::common_type_t<Q1, Q2> q) {
|
||||
requires requires { hypot(q.number(), q.number()); } || requires { std::hypot(q.number(), q.number()); };
|
||||
}
|
||||
{
|
||||
using type = std::common_type_t<Q1, Q2>;
|
||||
type xx = x;
|
||||
type yy = y;
|
||||
using std::hypot;
|
||||
return type(hypot(xx.number(), yy.number()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Computes the square root of the sum of the squares of x, y, and z,
|
||||
* without undue overflow or underflow at intermediate stages of the computation
|
||||
*/
|
||||
template<Quantity Q1, Quantity Q2, Quantity Q3>
|
||||
[[nodiscard]] inline std::common_type_t<Q1, Q2, Q3> hypot(const Q1& x, const Q2& y, const Q3& z) noexcept
|
||||
requires requires { typename std::common_type_t<Q1, Q2, Q3>; } &&
|
||||
requires(std::common_type_t<Q1, Q2, Q3> q) {
|
||||
requires requires { hypot(q.number(), q.number(), q.number()); } ||
|
||||
requires { std::hypot(q.number(), q.number(), q.number()); };
|
||||
}
|
||||
{
|
||||
using type = std::common_type_t<Q1, Q2, Q3>;
|
||||
type xx = x;
|
||||
type yy = y;
|
||||
type zz = z;
|
||||
using std::hypot;
|
||||
return type(hypot(xx.number(), yy.number(), zz.number()));
|
||||
}
|
||||
|
||||
} // namespace units
|
||||
|
@@ -405,11 +405,7 @@ public:
|
||||
requires(!Quantity<Value>) && (invoke_result_convertible_to_<rep, std::divides<>, const Value&, rep>)
|
||||
[[nodiscard]] friend constexpr Quantity auto operator/(const Value& v, const quantity& q)
|
||||
{
|
||||
gsl_ExpectsAudit(q.number() != quantity_values<rep>::zero());
|
||||
using dim = dim_invert<D>;
|
||||
using ret_unit = downcast_unit<dim, pow<-1>(U::mag)>;
|
||||
using ret = quantity<dim, ret_unit, std::invoke_result_t<std::divides<>, Value, rep>>;
|
||||
return ret(v / q.number());
|
||||
return detail::make_quantity<::units::reference<dim_one, ::units::one>{} / reference>(v / q.number());
|
||||
}
|
||||
|
||||
template<typename Value>
|
||||
@@ -444,7 +440,7 @@ public:
|
||||
};
|
||||
|
||||
// CTAD
|
||||
#if !UNITS_COMP_CLANG || UNITS_COMP_CLANG > 15
|
||||
#if !UNITS_COMP_CLANG || UNITS_COMP_CLANG > 16
|
||||
template<typename D, typename U, typename Rep>
|
||||
explicit(false) quantity(Rep&&)->quantity<D, U, Rep>;
|
||||
#endif
|
||||
|
@@ -28,6 +28,7 @@
|
||||
#include <units/concepts.h>
|
||||
#include <units/customization_points.h>
|
||||
#include <units/magnitude.h>
|
||||
#include <units/reference.h>
|
||||
|
||||
UNITS_DIAGNOSTIC_PUSH
|
||||
// warning C4244: 'argument': conversion from 'intmax_t' to 'T', possible loss of data with T=int
|
||||
@@ -49,17 +50,8 @@ class quantity_point_kind;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
inline constexpr Magnitude auto quantity_magnitude = std::enable_if_t<!Quantity<T>, magnitude<>>{};
|
||||
|
||||
template<typename D, typename U, typename Rep>
|
||||
inline constexpr Magnitude auto quantity_magnitude<quantity<D, U, Rep>> = [] {
|
||||
if constexpr (BaseDimension<D>) {
|
||||
return U::mag;
|
||||
} else {
|
||||
return D::base_units_ratio * U::mag / D::coherent_unit::mag;
|
||||
}
|
||||
}();
|
||||
template<Quantity Q>
|
||||
inline constexpr Magnitude auto quantity_magnitude = decltype(Q::reference)::mag;
|
||||
|
||||
template<Quantity Q>
|
||||
inline constexpr ratio quantity_ratio = as_ratio(quantity_magnitude<Q>);
|
||||
@@ -79,8 +71,8 @@ template<typename From, typename To>
|
||||
struct cast_traits;
|
||||
|
||||
template<typename From, typename To>
|
||||
requires common_type_with_<std::common_type_t<From, To>,
|
||||
std::intmax_t> struct cast_traits<From, To> {
|
||||
requires common_type_with_<std::common_type_t<From, To>, std::intmax_t>
|
||||
struct cast_traits<From, To> {
|
||||
using ratio_type = std::common_type_t<std::common_type_t<From, To>, std::intmax_t>;
|
||||
using rep_type = ratio_type;
|
||||
};
|
||||
|
@@ -43,42 +43,28 @@ constexpr ratio inverse(const ratio& r);
|
||||
/**
|
||||
* @brief Provides compile-time rational arithmetic support.
|
||||
*
|
||||
* This class is really similar to @c std::ratio but gets an additional `Exp`
|
||||
* template parameter that defines the exponent of the ratio. Another important
|
||||
* difference is the fact that the objects of that class are used as class NTTPs
|
||||
* rather then a type template parameter kind.
|
||||
* This class is really similar to @c std::ratio. An important difference is the fact that the objects of that class
|
||||
* are used as class NTTPs rather then a type template parameter kind.
|
||||
*/
|
||||
struct ratio {
|
||||
std::intmax_t num;
|
||||
std::intmax_t den;
|
||||
std::intmax_t exp;
|
||||
|
||||
constexpr explicit(false) ratio(std::intmax_t n, std::intmax_t d = 1, std::intmax_t e = 0) : num(n), den(d), exp(e)
|
||||
constexpr explicit(false) ratio(std::intmax_t n, std::intmax_t d = 1) : num(n), den(d)
|
||||
{
|
||||
gsl_Expects(den != 0);
|
||||
detail::normalize(num, den, exp);
|
||||
detail::normalize(num, den);
|
||||
}
|
||||
|
||||
[[nodiscard]] friend constexpr bool operator==(const ratio&, const ratio&) = default;
|
||||
|
||||
[[nodiscard]] friend constexpr auto operator<=>(const ratio& lhs, const ratio& rhs) { return (lhs - rhs).num <=> 0; }
|
||||
|
||||
[[nodiscard]] friend constexpr ratio operator-(const ratio& r) { return ratio(-r.num, r.den, r.exp); }
|
||||
[[nodiscard]] friend constexpr ratio operator-(const ratio& r) { return ratio(-r.num, r.den); }
|
||||
|
||||
[[nodiscard]] friend constexpr ratio operator+(ratio lhs, ratio rhs)
|
||||
{
|
||||
// First, get the inputs into a common exponent.
|
||||
const auto common_exp = std::min(lhs.exp, rhs.exp);
|
||||
auto commonify = [common_exp](ratio& r) {
|
||||
while (r.exp > common_exp) {
|
||||
r.num *= 10;
|
||||
--r.exp;
|
||||
}
|
||||
};
|
||||
commonify(lhs);
|
||||
commonify(rhs);
|
||||
|
||||
return ratio{lhs.num * rhs.den + lhs.den * rhs.num, lhs.den * rhs.den, common_exp};
|
||||
return ratio{lhs.num * rhs.den + lhs.den * rhs.num, lhs.den * rhs.den};
|
||||
}
|
||||
|
||||
[[nodiscard]] friend constexpr ratio operator-(const ratio& lhs, const ratio& rhs) { return lhs + (-rhs); }
|
||||
@@ -88,96 +74,27 @@ struct ratio {
|
||||
const std::intmax_t gcd1 = std::gcd(lhs.num, rhs.den);
|
||||
const std::intmax_t gcd2 = std::gcd(rhs.num, lhs.den);
|
||||
return ratio(detail::safe_multiply(lhs.num / gcd1, rhs.num / gcd2),
|
||||
detail::safe_multiply(lhs.den / gcd2, rhs.den / gcd1), lhs.exp + rhs.exp);
|
||||
detail::safe_multiply(lhs.den / gcd2, rhs.den / gcd1));
|
||||
}
|
||||
|
||||
[[nodiscard]] friend constexpr ratio operator/(const ratio& lhs, const ratio& rhs) { return lhs * inverse(rhs); }
|
||||
|
||||
[[nodiscard]] friend constexpr std::intmax_t numerator(const ratio& r)
|
||||
{
|
||||
std::intmax_t true_num = r.num;
|
||||
for (auto i = r.exp; i > 0; --i) {
|
||||
true_num *= 10;
|
||||
}
|
||||
return true_num;
|
||||
}
|
||||
|
||||
[[nodiscard]] friend constexpr std::intmax_t denominator(const ratio& r)
|
||||
{
|
||||
std::intmax_t true_den = r.den;
|
||||
for (auto i = r.exp; i < 0; ++i) {
|
||||
true_den *= 10;
|
||||
}
|
||||
return true_den;
|
||||
}
|
||||
};
|
||||
|
||||
[[nodiscard]] constexpr ratio inverse(const ratio& r) { return ratio(r.den, r.num, -r.exp); }
|
||||
[[nodiscard]] constexpr ratio inverse(const ratio& r) { return ratio(r.den, r.num); }
|
||||
|
||||
[[nodiscard]] constexpr bool is_integral(const ratio& r)
|
||||
{
|
||||
if (r.exp < 0) {
|
||||
return false;
|
||||
} else {
|
||||
return detail::gcdpow(r.num, r.exp, r.den) == r.den;
|
||||
}
|
||||
}
|
||||
[[nodiscard]] constexpr bool is_integral(const ratio& r) { return r.num % r.den == 0; }
|
||||
|
||||
namespace detail {
|
||||
|
||||
[[nodiscard]] constexpr auto make_exp_align(const ratio& r, std::intmax_t alignment)
|
||||
{
|
||||
gsl_Expects(alignment > 0);
|
||||
const std::intmax_t rem = r.exp % alignment;
|
||||
|
||||
if (rem == 0) { // already aligned
|
||||
return std::array{r.num, r.den, r.exp};
|
||||
}
|
||||
|
||||
if (r.exp > 0) { // remainder is positive
|
||||
return std::array{r.num * ipow10(rem), r.den, r.exp - rem};
|
||||
}
|
||||
|
||||
// remainder is negative
|
||||
return std::array{r.num, r.den * ipow10(-rem), r.exp - rem};
|
||||
}
|
||||
|
||||
template<std::intmax_t N>
|
||||
requires gt_zero<N>
|
||||
[[nodiscard]] constexpr ratio root(const ratio& r)
|
||||
{
|
||||
if constexpr (N == 1) {
|
||||
return r;
|
||||
} else {
|
||||
if (r.num == 0) {
|
||||
return ratio(0);
|
||||
}
|
||||
|
||||
const auto aligned = make_exp_align(r, N);
|
||||
return ratio(iroot<N>(aligned[0]), iroot<N>(aligned[1]), aligned[2] / N);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<std::intmax_t Num, std::intmax_t Den = 1>
|
||||
requires detail::non_zero<Den>
|
||||
template<std::intmax_t Num>
|
||||
[[nodiscard]] constexpr ratio pow(const ratio& r)
|
||||
{
|
||||
if constexpr (Num == 0) {
|
||||
return ratio(1);
|
||||
} else if constexpr (Num == Den) {
|
||||
} else if constexpr (Num == 1) {
|
||||
return r;
|
||||
} else {
|
||||
// simplify factors first and compute power for positive exponent
|
||||
constexpr std::intmax_t gcd = std::gcd(Num, Den);
|
||||
constexpr std::intmax_t num = detail::abs(Num / gcd);
|
||||
constexpr std::intmax_t den = detail::abs(Den / gcd);
|
||||
const ratio result = detail::pow_impl<Num>(r);
|
||||
|
||||
// integer root loses precision so do pow first
|
||||
const ratio result = detail::root<den>(detail::pow_impl<num>(r));
|
||||
|
||||
if constexpr (Num * Den < 0) { // account for negative exponent
|
||||
if constexpr (Num < 0) { // account for negative exponent
|
||||
return inverse(result);
|
||||
} else {
|
||||
return result;
|
||||
@@ -185,15 +102,11 @@ template<std::intmax_t Num, std::intmax_t Den = 1>
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr ratio sqrt(const ratio& r) { return pow<1, 2>(r); }
|
||||
|
||||
[[nodiscard]] constexpr ratio cbrt(const ratio& r) { return pow<1, 3>(r); }
|
||||
|
||||
// common_ratio
|
||||
[[nodiscard]] constexpr ratio common_ratio(const ratio& r1, const ratio& r2)
|
||||
{
|
||||
const auto res = detail::gcd_frac(r1.num, r1.den, r1.exp, r2.num, r2.den, r2.exp);
|
||||
return ratio(res[0], res[1], res[2]);
|
||||
const auto res = detail::gcd_frac(r1.num, r1.den, r2.num, r2.den);
|
||||
return ratio(res[0], res[1]);
|
||||
}
|
||||
|
||||
} // namespace units
|
||||
|
@@ -35,27 +35,21 @@ struct reference;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename D, typename D1, typename U1, typename D2, typename U2>
|
||||
using reference_multiply_impl =
|
||||
reference<D, downcast_unit<D, (U1::mag / dimension_unit<D1>::mag) * (U2::mag / dimension_unit<D2>::mag) *
|
||||
dimension_unit<D>::mag>>;
|
||||
template<Dimension D, Reference R1, Reference R2>
|
||||
using reference_multiply_impl = reference<D, downcast_unit<D, R1::mag * R2::mag / D::mag>>;
|
||||
|
||||
template<typename D, typename D1, typename U1, typename D2, typename U2>
|
||||
using reference_divide_impl =
|
||||
reference<D, downcast_unit<D, (U1::mag / dimension_unit<D1>::mag) / (U2::mag / dimension_unit<D2>::mag) *
|
||||
dimension_unit<D>::mag>>;
|
||||
template<typename D, Reference R1, Reference R2>
|
||||
using reference_divide_impl = reference<D, downcast_unit<D, R1::mag / R2::mag / D::mag>>;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<Reference R1, Reference R2>
|
||||
using reference_multiply =
|
||||
detail::reference_multiply_impl<dimension_multiply<typename R1::dimension, typename R2::dimension>,
|
||||
typename R1::dimension, typename R1::unit, typename R2::dimension, typename R2::unit>;
|
||||
detail::reference_multiply_impl<dimension_multiply<typename R1::dimension, typename R2::dimension>, R1, R2>;
|
||||
|
||||
template<Reference R1, Reference R2>
|
||||
using reference_divide =
|
||||
detail::reference_divide_impl<dimension_divide<typename R1::dimension, typename R2::dimension>,
|
||||
typename R1::dimension, typename R1::unit, typename R2::dimension, typename R2::unit>;
|
||||
detail::reference_divide_impl<dimension_divide<typename R1::dimension, typename R2::dimension>, R1, R2>;
|
||||
|
||||
/**
|
||||
* @brief The type for quantity references
|
||||
@@ -100,6 +94,7 @@ template<Dimension D, UnitOf<D> U>
|
||||
struct reference {
|
||||
using dimension = D;
|
||||
using unit = U;
|
||||
static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto mag = dimension::mag * unit::mag;
|
||||
|
||||
// Hidden Friends
|
||||
// Below friend functions are to be found via argument-dependent lookup only
|
||||
|
@@ -24,6 +24,7 @@
|
||||
|
||||
#include <units/bits/derived_symbol_text.h>
|
||||
#include <units/bits/external/downcasting.h>
|
||||
#include <units/bits/external/type_traits.h>
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include <units/bits/derived_scaled_unit.h>
|
||||
@@ -57,6 +58,9 @@ inline constexpr bool can_be_prefixed = false;
|
||||
*
|
||||
* @tparam M a Magnitude representing the (relative) size of this unit
|
||||
* @tparam U a unit to use as a reference for this dimension
|
||||
*
|
||||
* @note U cannot be constrained with Unit as for some specializations (i.e. named_unit)
|
||||
* it gets the incomplete child's type with the CRTP idiom.
|
||||
*/
|
||||
template<Magnitude auto M, typename U>
|
||||
struct scaled_unit : downcast_base<scaled_unit<M, U>> {
|
||||
@@ -80,7 +84,7 @@ struct same_unit_reference : is_same<typename U1::reference, typename U2::refere
|
||||
* @tparam Symbol a short text representation of the unit
|
||||
*/
|
||||
template<typename Child, basic_symbol_text Symbol>
|
||||
struct named_unit : downcast_dispatch<Child, scaled_unit<as_magnitude<1>(), Child>> {
|
||||
struct named_unit : downcast_dispatch<Child, scaled_unit<mag<1>(), Child>> {
|
||||
static constexpr auto symbol = Symbol;
|
||||
};
|
||||
|
||||
@@ -126,7 +130,7 @@ struct prefixed_unit : downcast_dispatch<Child, scaled_unit<P::mag * U::mag, typ
|
||||
* @tparam Child inherited class type used by the downcasting facility (CRTP Idiom)
|
||||
*/
|
||||
template<typename Child>
|
||||
struct derived_unit : downcast_dispatch<Child, scaled_unit<as_magnitude<1>(), Child>> {};
|
||||
struct derived_unit : downcast_dispatch<Child, scaled_unit<mag<1>(), Child>> {};
|
||||
|
||||
/**
|
||||
* @brief A unit with a deduced ratio and symbol
|
||||
@@ -173,12 +177,8 @@ struct alias_unit : U {
|
||||
* @tparam P prefix to be appied to the reference unit
|
||||
* @tparam AU reference alias unit
|
||||
*/
|
||||
// TODO gcc bug: 95015
|
||||
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95015
|
||||
// template<Unit U, Prefix P, AliasUnit AU>
|
||||
// requires (!AliasUnit<U>)
|
||||
template<Unit U, Prefix P, NamedUnit AU>
|
||||
requires detail::can_be_prefixed<AU>
|
||||
template<Unit U, Prefix P, AliasUnit AU>
|
||||
requires(!AliasUnit<U>)
|
||||
struct prefixed_alias_unit : U {
|
||||
static constexpr auto symbol = P::symbol + AU::symbol;
|
||||
};
|
||||
@@ -188,7 +188,10 @@ struct prefixed_alias_unit : U {
|
||||
*
|
||||
* Used as a coherent unit of an unknown dimension.
|
||||
*/
|
||||
struct unknown_coherent_unit : derived_unit<unknown_coherent_unit> {};
|
||||
template<Exponent... Es>
|
||||
struct unknown_coherent_unit :
|
||||
downcast_dispatch<unknown_coherent_unit<Es...>,
|
||||
scaled_unit<detail::absolute_magnitude(exponent_list<Es...>()), unknown_coherent_unit<Es...>>> {};
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
@@ -30,6 +30,7 @@ function(__check_libcxx_in_use variable)
|
||||
set(${variable} ${${variable}} PARENT_SCOPE)
|
||||
|
||||
list(POP_BACK CMAKE_MESSAGE_INDENT)
|
||||
|
||||
if(${variable})
|
||||
message(CHECK_PASS "found")
|
||||
else()
|
||||
@@ -39,15 +40,21 @@ function(__check_libcxx_in_use variable)
|
||||
endfunction()
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
|
||||
if(UNITS_USE_LIBFMT)
|
||||
find_dependency(fmt)
|
||||
endif()
|
||||
|
||||
find_dependency(gsl-lite)
|
||||
|
||||
# add range-v3 dependency only for clang + libc++
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
__check_libcxx_in_use(__units_libcxx)
|
||||
|
||||
if(__units_libcxx AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "14")
|
||||
find_dependency(range-v3)
|
||||
endif()
|
||||
|
||||
unset(__units_libcxx)
|
||||
endif()
|
||||
|
||||
|
@@ -26,13 +26,13 @@
|
||||
|
||||
namespace units::isq::iec80000 {
|
||||
|
||||
struct kibi : prefix<kibi, "Ki", pow<10>(as_magnitude<2>())> {};
|
||||
struct mebi : prefix<mebi, "Mi", pow<20>(as_magnitude<2>())> {};
|
||||
struct gibi : prefix<gibi, "Gi", pow<30>(as_magnitude<2>())> {};
|
||||
struct tebi : prefix<tebi, "Ti", pow<40>(as_magnitude<2>())> {};
|
||||
struct pebi : prefix<pebi, "Pi", pow<50>(as_magnitude<2>())> {};
|
||||
struct exbi : prefix<exbi, "Ei", pow<60>(as_magnitude<2>())> {};
|
||||
struct zebi : prefix<zebi, "Zi", pow<70>(as_magnitude<2>())> {};
|
||||
struct yobi : prefix<yobi, "Yi", pow<80>(as_magnitude<2>())> {};
|
||||
struct kibi : prefix<kibi, "Ki", pow<10>(mag<2>())> {};
|
||||
struct mebi : prefix<mebi, "Mi", pow<20>(mag<2>())> {};
|
||||
struct gibi : prefix<gibi, "Gi", pow<30>(mag<2>())> {};
|
||||
struct tebi : prefix<tebi, "Ti", pow<40>(mag<2>())> {};
|
||||
struct pebi : prefix<pebi, "Pi", pow<50>(mag<2>())> {};
|
||||
struct exbi : prefix<exbi, "Ei", pow<60>(mag<2>())> {};
|
||||
struct zebi : prefix<zebi, "Zi", pow<70>(mag<2>())> {};
|
||||
struct yobi : prefix<yobi, "Yi", pow<80>(mag<2>())> {};
|
||||
|
||||
} // namespace units::isq::iec80000
|
||||
|
@@ -53,7 +53,7 @@ struct tebibit : prefixed_unit<tebibit, tebi, bit> {};
|
||||
struct pebibit : prefixed_unit<pebibit, pebi, bit> {};
|
||||
struct exbibit : prefixed_unit<exbibit, exbi, bit> {};
|
||||
|
||||
struct byte : named_scaled_unit<byte, "B", as_magnitude<8>(), bit> {};
|
||||
struct byte : named_scaled_unit<byte, "B", mag<8>(), bit> {};
|
||||
|
||||
struct kilobyte : prefixed_unit<kilobyte, si::kilo, byte> {};
|
||||
struct megabyte : prefixed_unit<megabyte, si::mega, byte> {};
|
||||
|
@@ -40,7 +40,7 @@ namespace units::isq::si::fps {
|
||||
struct poundal : named_unit<poundal, "pdl"> {};
|
||||
|
||||
// https://en.wikipedia.org/wiki/Pound_(force)
|
||||
struct pound_force : named_scaled_unit<pound_force, "lbf", as_magnitude<ratio(32'174'049, 1'000'000)>(), poundal> {};
|
||||
struct pound_force : named_scaled_unit<pound_force, "lbf", mag<ratio(32'174'049, 1'000'000)>(), poundal> {};
|
||||
|
||||
struct kilopound_force : prefixed_unit<kilopound_force, si::kilo, pound_force> {};
|
||||
|
||||
|
@@ -48,7 +48,7 @@ struct thousandth : alias_unit<thou, "thou"> {};
|
||||
|
||||
struct kiloyard : prefixed_unit<kiloyard, si::kilo, yard> {};
|
||||
|
||||
struct nautical_mile : named_scaled_unit<nautical_mile, "nmi", as_magnitude<2'000>(), yard> {};
|
||||
struct nautical_mile : named_scaled_unit<nautical_mile, "nmi", mag<2'000>(), yard> {};
|
||||
|
||||
struct dim_length : isq::dim_length<foot> {};
|
||||
|
||||
|
@@ -35,28 +35,28 @@
|
||||
namespace units::isq::si::fps {
|
||||
|
||||
// https://en.wikipedia.org/wiki/Pound_(mass)
|
||||
struct pound : named_scaled_unit<pound, "lb", as_magnitude<ratio(45'359'237, 100'000'000)>(), si::kilogram> {};
|
||||
struct pound : named_scaled_unit<pound, "lb", mag<ratio(45'359'237, 100'000'000)>(), si::kilogram> {};
|
||||
|
||||
struct dim_mass : isq::dim_mass<pound> {};
|
||||
|
||||
template<UnitOf<dim_mass> U, Representation Rep = double>
|
||||
using mass = quantity<dim_mass, U, Rep>;
|
||||
|
||||
struct grain : named_scaled_unit<grain, "gr", as_magnitude<ratio(1, 7000)>(), pound> {};
|
||||
struct grain : named_scaled_unit<grain, "gr", mag<ratio(1, 7000)>(), pound> {};
|
||||
|
||||
struct dram : named_scaled_unit<dram, "dr", as_magnitude<ratio(1, 256)>(), pound> {};
|
||||
struct dram : named_scaled_unit<dram, "dr", mag<ratio(1, 256)>(), pound> {};
|
||||
|
||||
struct ounce : named_scaled_unit<ounce, "oz", as_magnitude<ratio(1, 16)>(), pound> {};
|
||||
struct ounce : named_scaled_unit<ounce, "oz", mag<ratio(1, 16)>(), pound> {};
|
||||
|
||||
struct stone : named_scaled_unit<stone, "st", as_magnitude<14>(), pound> {};
|
||||
struct stone : named_scaled_unit<stone, "st", mag<14>(), pound> {};
|
||||
|
||||
struct quarter : named_scaled_unit<quarter, "qr", as_magnitude<28>(), pound> {};
|
||||
struct quarter : named_scaled_unit<quarter, "qr", mag<28>(), pound> {};
|
||||
|
||||
struct hundredweight : named_scaled_unit<hundredweight, "cwt", as_magnitude<112>(), pound> {};
|
||||
struct hundredweight : named_scaled_unit<hundredweight, "cwt", mag<112>(), pound> {};
|
||||
|
||||
struct short_ton : named_scaled_unit<short_ton, "ton (short)", as_magnitude<2'000>(), pound> {};
|
||||
struct short_ton : named_scaled_unit<short_ton, "ton (short)", mag<2'000>(), pound> {};
|
||||
|
||||
struct long_ton : named_scaled_unit<long_ton, "ton (long)", as_magnitude<2'240>(), pound> {};
|
||||
struct long_ton : named_scaled_unit<long_ton, "ton (long)", mag<2'240>(), pound> {};
|
||||
|
||||
#ifndef UNITS_NO_LITERALS
|
||||
|
||||
|
@@ -42,7 +42,7 @@ struct dim_power : isq::dim_power<dim_power, foot_poundal_per_second, dim_length
|
||||
struct foot_pound_force_per_second :
|
||||
derived_scaled_unit<foot_pound_force_per_second, dim_power, foot, pound_force, second> {};
|
||||
|
||||
struct horse_power : named_scaled_unit<horse_power, "hp", as_magnitude<550>(), foot_pound_force_per_second> {};
|
||||
struct horse_power : named_scaled_unit<horse_power, "hp", mag<550>(), foot_pound_force_per_second> {};
|
||||
|
||||
template<UnitOf<dim_power> U, Representation Rep = double>
|
||||
using power = quantity<dim_power, U, Rep>;
|
||||
|
@@ -44,11 +44,10 @@ template<UnitOf<dim_pressure> U, Representation Rep = double>
|
||||
using pressure = quantity<dim_pressure, U, Rep>;
|
||||
|
||||
struct pound_force_per_foot_sq :
|
||||
named_scaled_unit<pound_force_per_foot_sq, "lbf ft2", as_magnitude<ratio(32'174'049, 1'000'000)>(),
|
||||
poundal_per_foot_sq> {};
|
||||
named_scaled_unit<pound_force_per_foot_sq, "lbf ft2", mag<ratio(32'174'049, 1'000'000)>(), poundal_per_foot_sq> {};
|
||||
|
||||
struct pound_force_per_inch_sq :
|
||||
named_scaled_unit<pound_force_per_inch_sq, "psi", as_magnitude<ratio(1, 144)>(), pound_force_per_foot_sq> {};
|
||||
named_scaled_unit<pound_force_per_inch_sq, "psi", mag<ratio(1, 144)>(), pound_force_per_foot_sq> {};
|
||||
|
||||
struct kilopound_force_per_inch_sq : prefixed_unit<kilopound_force_per_inch_sq, si::kilo, pound_force_per_inch_sq> {};
|
||||
|
||||
|
@@ -37,7 +37,7 @@ namespace units::isq::si::hep {
|
||||
// effective cross-sectional area according to EU council directive 80/181/EEC
|
||||
// https://eur-lex.europa.eu/legal-content/EN/TXT/PDF/?uri=CELEX:01980L0181-20090527#page=10
|
||||
// https://www.fedlex.admin.ch/eli/cc/1994/3109_3109_3109/de
|
||||
struct barn : named_scaled_unit<barn, "b", as_magnitude<ratio(1, 1, -28)>(), square_metre> {};
|
||||
struct barn : named_scaled_unit<barn, "b", mag_power<10, -28>(), square_metre> {};
|
||||
struct yocto_barn : prefixed_unit<yocto_barn, yocto, barn> {};
|
||||
struct zepto_barn : prefixed_unit<zepto_barn, zepto, barn> {};
|
||||
struct atto_barn : prefixed_unit<atto_barn, atto, barn> {};
|
||||
|
@@ -44,7 +44,7 @@ namespace units::isq::si::hep {
|
||||
|
||||
struct eV_per_c2 :
|
||||
named_scaled_unit<eV_per_c2, basic_symbol_text{"eV/c²", "eV/c^2"},
|
||||
as_magnitude<ratio(17'826'619'216'279, 1'000'000'000'000, -35)>(), kilogram> {};
|
||||
mag<ratio(17'826'619'216'279, 1'000'000'000'000)>() * mag_power<10, -35>(), kilogram> {};
|
||||
struct feV_per_c2 : prefixed_unit<feV_per_c2, femto, eV_per_c2> {};
|
||||
struct peV_per_c2 : prefixed_unit<peV_per_c2, pico, eV_per_c2> {};
|
||||
struct neV_per_c2 : prefixed_unit<neV_per_c2, nano, eV_per_c2> {};
|
||||
@@ -60,11 +60,14 @@ struct PeV_per_c2 : prefixed_unit<PeV_per_c2, peta, eV_per_c2> {};
|
||||
struct EeV_per_c2 : prefixed_unit<EeV_per_c2, exa, eV_per_c2> {};
|
||||
struct YeV_per_c2 : prefixed_unit<YeV_per_c2, yotta, eV_per_c2> {};
|
||||
struct electron_mass :
|
||||
named_scaled_unit<eV_per_c2, "m_e", as_magnitude<ratio(9'109'383'701'528, 1'000'000'000'000, -31)>(), kilogram> {};
|
||||
named_scaled_unit<eV_per_c2, "m_e", mag<ratio(9'109'383'701'528, 1'000'000'000'000)>() * mag_power<10, -31>(),
|
||||
kilogram> {};
|
||||
struct proton_mass :
|
||||
named_scaled_unit<eV_per_c2, "m_p", as_magnitude<ratio(1'672'621'923'695, 1'000'000'000'000, -27)>(), kilogram> {};
|
||||
named_scaled_unit<eV_per_c2, "m_p", mag<ratio(1'672'621'923'695, 1'000'000'000'000)>() * mag_power<10, -27>(),
|
||||
kilogram> {};
|
||||
struct neutron_mass :
|
||||
named_scaled_unit<eV_per_c2, "m_n", as_magnitude<ratio(1'674'927'498'049, 1'000'000'000'000, -27)>(), kilogram> {};
|
||||
named_scaled_unit<eV_per_c2, "m_n", mag<ratio(1'674'927'498'049, 1'000'000'000'000)>() * mag_power<10, -27>(),
|
||||
kilogram> {};
|
||||
|
||||
struct dim_mass : isq::dim_mass<eV_per_c2> {};
|
||||
|
||||
|
@@ -41,7 +41,7 @@ namespace units::isq::si::hep {
|
||||
struct kilogram_metre_per_second : derived_unit<kilogram_metre_per_second> {};
|
||||
|
||||
struct eV_per_c :
|
||||
named_scaled_unit<eV_per_c, "eV/c", as_magnitude<ratio(5'344'285'992'678, 1'000'000'000'000, -35)>(),
|
||||
named_scaled_unit<eV_per_c, "eV/c", mag<ratio(5'344'285'992'678, 1'000'000'000'000)>() * mag_power<10, -35>(),
|
||||
kilogram_metre_per_second> {};
|
||||
struct feV_per_c : prefixed_unit<feV_per_c, femto, eV_per_c> {};
|
||||
struct peV_per_c : prefixed_unit<peV_per_c, pico, eV_per_c> {};
|
||||
|
@@ -36,13 +36,13 @@
|
||||
namespace units::isq::si::iau {
|
||||
|
||||
// https://en.wikipedia.org/wiki/Light-year
|
||||
struct light_year : named_scaled_unit<light_year, "ly", as_magnitude<9460730472580800>(), si::metre> {};
|
||||
struct light_year : named_scaled_unit<light_year, "ly", mag<9460730472580800>(), si::metre> {};
|
||||
|
||||
// https://en.wikipedia.org/wiki/Parsec
|
||||
struct parsec : named_scaled_unit<parsec, "pc", as_magnitude<30'856'775'814'913'673>(), si::metre> {};
|
||||
struct parsec : named_scaled_unit<parsec, "pc", mag<30'856'775'814'913'673>(), si::metre> {};
|
||||
|
||||
// https://en.wikipedia.org/wiki/Angstrom
|
||||
struct angstrom : named_scaled_unit<angstrom, "angstrom", as_magnitude<ratio(1, 1, -10)>(), si::metre> {};
|
||||
struct angstrom : named_scaled_unit<angstrom, "angstrom", mag_power<10, -10>(), si::metre> {};
|
||||
|
||||
#ifndef UNITS_NO_LITERALS
|
||||
|
||||
|
@@ -35,10 +35,10 @@
|
||||
namespace units::isq::si::imperial {
|
||||
|
||||
// https://en.wikipedia.org/wiki/Chain_(unit)
|
||||
struct chain : named_scaled_unit<chain, "ch", as_magnitude<22>(), si::international::yard> {};
|
||||
struct chain : named_scaled_unit<chain, "ch", mag<22>(), si::international::yard> {};
|
||||
|
||||
// https://en.wikipedia.org/wiki/Rod_(unit)
|
||||
struct rod : named_scaled_unit<rod, "rd", as_magnitude<ratio(1, 4)>(), chain> {};
|
||||
struct rod : named_scaled_unit<rod, "rd", mag<ratio(1, 4)>(), chain> {};
|
||||
|
||||
#ifndef UNITS_NO_LITERALS
|
||||
|
||||
|
@@ -37,30 +37,30 @@ namespace units::isq::si::international {
|
||||
|
||||
// si::international yard
|
||||
// https://en.wikipedia.org/wiki/International_yard_and_pound
|
||||
struct yard : named_scaled_unit<yard, "yd", as_magnitude<ratio(9'144, 1'000, -1)>(), si::metre> {};
|
||||
struct yard : named_scaled_unit<yard, "yd", mag<ratio{9'144, 10'000}>(), si::metre> {};
|
||||
|
||||
// si::international foot
|
||||
// https://en.wikipedia.org/wiki/Foot_(unit)#International_foot
|
||||
struct foot : named_scaled_unit<foot, "ft", as_magnitude<ratio(1, 3)>(), yard> {};
|
||||
struct foot : named_scaled_unit<foot, "ft", mag<ratio(1, 3)>(), yard> {};
|
||||
|
||||
// https://en.wikipedia.org/wiki/Fathom#International_fathom
|
||||
struct fathom : named_scaled_unit<fathom, "fathom", as_magnitude<2>(), yard> {};
|
||||
struct fathom : named_scaled_unit<fathom, "fathom", mag<2>(), yard> {};
|
||||
|
||||
// si::international inch
|
||||
// https://en.wikipedia.org/wiki/Inch#Equivalences
|
||||
struct inch : named_scaled_unit<inch, "in", as_magnitude<ratio(1, 36)>(), yard> {};
|
||||
struct inch : named_scaled_unit<inch, "in", mag<ratio(1, 36)>(), yard> {};
|
||||
|
||||
// intrnational mile
|
||||
// https://en.wikipedia.org/wiki/Mile#International_mile
|
||||
struct mile : named_scaled_unit<mile, "mi", as_magnitude<ratio(25'146, 15'625)>(), si::kilometre> {};
|
||||
struct mile : named_scaled_unit<mile, "mi", mag<ratio(25'146, 15'625)>(), si::kilometre> {};
|
||||
|
||||
// si::international nautical mile
|
||||
// https://en.wikipedia.org/wiki/Nautical_mile
|
||||
struct nautical_mile : named_scaled_unit<nautical_mile, "mi(naut)", as_magnitude<1852>(), si::metre> {};
|
||||
struct nautical_mile : named_scaled_unit<nautical_mile, "mi(naut)", mag<1852>(), si::metre> {};
|
||||
|
||||
// thou
|
||||
// https://en.wikipedia.org/wiki/Thousandth_of_an_inch
|
||||
struct thou : named_scaled_unit<thou, "thou", as_magnitude<ratio(1, 1000)>(), inch> {};
|
||||
struct thou : named_scaled_unit<thou, "thou", mag<ratio(1, 1000)>(), inch> {};
|
||||
|
||||
// mil - different name for thou
|
||||
// https://en.wikipedia.org/wiki/Thousandth_of_an_inch
|
||||
|
@@ -37,12 +37,13 @@ namespace units::isq::si::typographic {
|
||||
|
||||
// TODO Conflicts with (https://en.wikipedia.org/wiki/Pica_(typography)), verify correctness of below conversion factors
|
||||
// and provide hyperlinks to definitions
|
||||
struct pica_comp :
|
||||
named_scaled_unit<pica_comp, "pica(comp)", as_magnitude<ratio(4233333, 1000000, -3)>(), si::metre> {};
|
||||
struct pica_prn : named_scaled_unit<pica_prn, "pica(prn)", as_magnitude<ratio(2108759, 500000, -3)>(), si::metre> {};
|
||||
struct pica_comp : named_scaled_unit<pica_comp, "pica(comp)", mag<4'233'333>() * mag_power<10, -9>(), si::metre> {};
|
||||
struct pica_prn :
|
||||
named_scaled_unit<pica_prn, "pica(prn)", mag<ratio(2108759, 500000)>() * mag_power<10, -3>(), si::metre> {};
|
||||
struct point_comp :
|
||||
named_scaled_unit<point_comp, "point(comp)", as_magnitude<ratio(1763889, 500000, -4)>(), si::metre> {};
|
||||
struct point_prn : named_scaled_unit<point_prn, "point(prn)", as_magnitude<ratio(1757299, 500000, -4)>(), si::metre> {};
|
||||
named_scaled_unit<point_comp, "point(comp)", mag<ratio(1763889, 500000)>() * mag_power<10, -4>(), si::metre> {};
|
||||
struct point_prn :
|
||||
named_scaled_unit<point_prn, "point(prn)", mag<ratio(1757299, 500000)>() * mag_power<10, -4>(), si::metre> {};
|
||||
|
||||
#ifndef UNITS_NO_LITERALS
|
||||
|
||||
|
@@ -36,14 +36,14 @@ namespace units::isq::si::uscs {
|
||||
|
||||
// https://en.wikipedia.org/wiki/Foot_(unit)#US_survey_foot
|
||||
// https://www.nist.gov/pml/special-publication-811/nist-guide-si-appendix-b-conversion-factors#B6
|
||||
struct foot : named_scaled_unit<foot, "ft(us)", as_magnitude<ratio(1'200, 3'937)>(), si::metre> {};
|
||||
struct foot : named_scaled_unit<foot, "ft(us)", mag<ratio(1'200, 3'937)>(), si::metre> {};
|
||||
|
||||
// https://www.nist.gov/pml/special-publication-811/nist-guide-si-appendix-b-conversion-factors#B6
|
||||
struct fathom : named_scaled_unit<fathom, "fathom(us)", as_magnitude<6>(), foot> {};
|
||||
struct fathom : named_scaled_unit<fathom, "fathom(us)", mag<6>(), foot> {};
|
||||
|
||||
// https://en.wikipedia.org/wiki/Mile#U.S._survey_mile
|
||||
// https://www.nist.gov/pml/special-publication-811/nist-guide-si-appendix-b-conversion-factors#B6
|
||||
struct mile : named_scaled_unit<mile, "mi(us)", as_magnitude<5280>(), foot> {};
|
||||
struct mile : named_scaled_unit<mile, "mi(us)", mag<5280>(), foot> {};
|
||||
|
||||
#ifndef UNITS_NO_LITERALS
|
||||
|
||||
|
@@ -58,7 +58,7 @@ struct exakatal : prefixed_unit<exakatal, exa, katal> {};
|
||||
struct zettakatal : prefixed_unit<zettakatal, zetta, katal> {};
|
||||
struct yottakatal : prefixed_unit<yottakatal, yotta, katal> {};
|
||||
|
||||
struct enzyme_unit : named_scaled_unit<enzyme_unit, "U", as_magnitude<ratio(1, 60, -6)>(), katal> {};
|
||||
struct enzyme_unit : named_scaled_unit<enzyme_unit, "U", mag<ratio(1, 60)>() * mag_power<10, -6>(), katal> {};
|
||||
|
||||
struct dim_catalytic_activity :
|
||||
isq::dim_catalytic_activity<dim_catalytic_activity, katal, dim_time, dim_amount_of_substance> {};
|
||||
|
@@ -56,7 +56,7 @@ struct yottajoule : prefixed_unit<yottajoule, yotta, joule> {};
|
||||
// N.B. electron charge (and eV) is an exact constant:
|
||||
// https://www.bipm.org/documents/20126/41483022/SI-Brochure-9.pdf#page=147
|
||||
struct electronvolt :
|
||||
named_scaled_unit<electronvolt, "eV", as_magnitude<ratio(1'602'176'634, 1'000'000'000, -19)>(), joule> {};
|
||||
named_scaled_unit<electronvolt, "eV", mag<ratio(1'602'176'634, 1'000'000'000)>() * mag_power<10, -19>(), joule> {};
|
||||
struct gigaelectronvolt : prefixed_unit<gigaelectronvolt, giga, electronvolt> {};
|
||||
|
||||
struct dim_energy : isq::dim_energy<dim_energy, joule, dim_force, dim_length> {};
|
||||
|
@@ -56,7 +56,7 @@ struct exametre : prefixed_unit<exametre, exa, metre> {};
|
||||
struct zettametre : prefixed_unit<zettametre, zetta, metre> {};
|
||||
struct yottametre : prefixed_unit<yottametre, yotta, metre> {};
|
||||
|
||||
struct astronomical_unit : named_scaled_unit<astronomical_unit, "au", as_magnitude<149'597'870'700>(), metre> {};
|
||||
struct astronomical_unit : named_scaled_unit<astronomical_unit, "au", mag<149'597'870'700>(), metre> {};
|
||||
|
||||
struct dim_length : isq::dim_length<metre> {};
|
||||
|
||||
|
@@ -36,7 +36,7 @@ namespace units::isq::si {
|
||||
|
||||
// TODO Is this correct? Should we account for steradian here? How?
|
||||
|
||||
struct lumen : named_scaled_unit<lumen, "lm", as_magnitude<ratio(1, 683)>(), watt> {};
|
||||
struct lumen : named_scaled_unit<lumen, "lm", mag<ratio(1, 683)>(), watt> {};
|
||||
|
||||
using dim_luminous_flux = dim_power;
|
||||
|
||||
|
@@ -56,7 +56,7 @@ struct exatesla : prefixed_unit<exatesla, exa, tesla> {};
|
||||
struct zettatesla : prefixed_unit<zettatesla, zetta, tesla> {};
|
||||
struct yottatesla : prefixed_unit<yottatesla, yotta, tesla> {};
|
||||
|
||||
struct gauss : named_scaled_unit<gauss, "G", as_magnitude<ratio(1, 10'000)>(), tesla> {};
|
||||
struct gauss : named_scaled_unit<gauss, "G", mag<ratio(1, 10'000)>(), tesla> {};
|
||||
|
||||
struct dim_magnetic_induction :
|
||||
isq::dim_magnetic_induction<dim_magnetic_induction, tesla, dim_voltage, dim_time, dim_length> {};
|
||||
|
@@ -79,7 +79,8 @@ struct zettatonne : prefixed_unit<zettatonne, zetta, tonne> {};
|
||||
struct yottatonne : prefixed_unit<yottatonne, yotta, tonne> {};
|
||||
|
||||
struct dalton :
|
||||
named_scaled_unit<dalton, "Da", as_magnitude<ratio(16'605'390'666'050, 10'000'000'000'000, -27)>(), kilogram> {};
|
||||
named_scaled_unit<dalton, "Da", mag<ratio(16'605'390'666'050, 10'000'000'000'000)>() * mag_power<10, -27>(),
|
||||
kilogram> {};
|
||||
|
||||
struct dim_mass : isq::dim_mass<kilogram> {};
|
||||
|
||||
|
@@ -27,26 +27,26 @@
|
||||
namespace units::isq::si {
|
||||
|
||||
// clang-format off
|
||||
struct yocto : prefix<yocto, "y", pow<-24>(as_magnitude<10>())> {};
|
||||
struct zepto : prefix<zepto, "z", pow<-21>(as_magnitude<10>())> {};
|
||||
struct atto : prefix<atto, "a", pow<-18>(as_magnitude<10>())> {};
|
||||
struct femto : prefix<femto, "f", pow<-15>(as_magnitude<10>())> {};
|
||||
struct pico : prefix<pico, "p", pow<-12>(as_magnitude<10>())> {};
|
||||
struct nano : prefix<nano, "n", pow<-9>(as_magnitude<10>())> {};
|
||||
struct micro : prefix<micro, basic_symbol_text{"\u00b5", "u"}, pow<-6>(as_magnitude<10>())> {};
|
||||
struct milli : prefix<milli, "m", pow<-3>(as_magnitude<10>())> {};
|
||||
struct centi : prefix<centi, "c", pow<-2>(as_magnitude<10>())> {};
|
||||
struct deci : prefix<deci, "d", pow<-1>(as_magnitude<10>())> {};
|
||||
struct deca : prefix<deca, "da", pow<1>(as_magnitude<10>())> {};
|
||||
struct hecto : prefix<hecto, "h", pow<2>(as_magnitude<10>())> {};
|
||||
struct kilo : prefix<kilo, "k", pow<3>(as_magnitude<10>())> {};
|
||||
struct mega : prefix<mega, "M", pow<6>(as_magnitude<10>())> {};
|
||||
struct giga : prefix<giga, "G", pow<9>(as_magnitude<10>())> {};
|
||||
struct tera : prefix<tera, "T", pow<12>(as_magnitude<10>())> {};
|
||||
struct peta : prefix<peta, "P", pow<15>(as_magnitude<10>())> {};
|
||||
struct exa : prefix<exa, "E", pow<18>(as_magnitude<10>())> {};
|
||||
struct zetta : prefix<zetta, "Z", pow<21>(as_magnitude<10>())> {};
|
||||
struct yotta : prefix<yotta, "Y", pow<24>(as_magnitude<10>())> {};
|
||||
struct yocto : prefix<yocto, "y", pow<-24>(mag<10>())> {};
|
||||
struct zepto : prefix<zepto, "z", pow<-21>(mag<10>())> {};
|
||||
struct atto : prefix<atto, "a", pow<-18>(mag<10>())> {};
|
||||
struct femto : prefix<femto, "f", pow<-15>(mag<10>())> {};
|
||||
struct pico : prefix<pico, "p", pow<-12>(mag<10>())> {};
|
||||
struct nano : prefix<nano, "n", pow<-9>(mag<10>())> {};
|
||||
struct micro : prefix<micro, basic_symbol_text{"\u00b5", "u"}, pow<-6>(mag<10>())> {};
|
||||
struct milli : prefix<milli, "m", pow<-3>(mag<10>())> {};
|
||||
struct centi : prefix<centi, "c", pow<-2>(mag<10>())> {};
|
||||
struct deci : prefix<deci, "d", pow<-1>(mag<10>())> {};
|
||||
struct deca : prefix<deca, "da", pow<1>(mag<10>())> {};
|
||||
struct hecto : prefix<hecto, "h", pow<2>(mag<10>())> {};
|
||||
struct kilo : prefix<kilo, "k", pow<3>(mag<10>())> {};
|
||||
struct mega : prefix<mega, "M", pow<6>(mag<10>())> {};
|
||||
struct giga : prefix<giga, "G", pow<9>(mag<10>())> {};
|
||||
struct tera : prefix<tera, "T", pow<12>(mag<10>())> {};
|
||||
struct peta : prefix<peta, "P", pow<15>(mag<10>())> {};
|
||||
struct exa : prefix<exa, "E", pow<18>(mag<10>())> {};
|
||||
struct zetta : prefix<zetta, "Z", pow<21>(mag<10>())> {};
|
||||
struct yotta : prefix<yotta, "Y", pow<24>(mag<10>())> {};
|
||||
// clang-format on
|
||||
|
||||
} // namespace units::isq::si
|
||||
|
@@ -43,9 +43,9 @@ struct picosecond : prefixed_unit<picosecond, pico, second> {};
|
||||
struct nanosecond : prefixed_unit<nanosecond, nano, second> {};
|
||||
struct microsecond : prefixed_unit<microsecond, micro, second> {};
|
||||
struct millisecond : prefixed_unit<millisecond, milli, second> {};
|
||||
struct minute : named_scaled_unit<minute, "min", as_magnitude<60>(), second> {};
|
||||
struct hour : named_scaled_unit<hour, "h", as_magnitude<60>(), minute> {};
|
||||
struct day : named_scaled_unit<day, "d", as_magnitude<24>(), hour> {};
|
||||
struct minute : named_scaled_unit<minute, "min", mag<60>(), second> {};
|
||||
struct hour : named_scaled_unit<hour, "h", mag<60>(), minute> {};
|
||||
struct day : named_scaled_unit<day, "d", mag<24>(), hour> {};
|
||||
|
||||
struct dim_time : isq::dim_time<second> {};
|
||||
|
||||
|
@@ -84,7 +84,7 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]")
|
||||
{
|
||||
SECTION("in terms of base units")
|
||||
{
|
||||
const length<scaled_unit<pow<6>(as_magnitude<10>()), metre>> q(123);
|
||||
const length<scaled_unit<pow<6>(mag<10>()), metre>> q(123);
|
||||
os << q;
|
||||
|
||||
SECTION("iostream") { CHECK(os.str() == "123 Mm"); }
|
||||
@@ -96,7 +96,7 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]")
|
||||
|
||||
SECTION("in terms of derived units")
|
||||
{
|
||||
const energy<scaled_unit<pow<-2>(as_magnitude<10>()), joule>> q(60);
|
||||
const energy<scaled_unit<pow<-2>(mag<10>()), joule>> q(60);
|
||||
os << q;
|
||||
|
||||
SECTION("iostream") { CHECK(os.str() == "60 cJ"); }
|
||||
|
@@ -327,7 +327,7 @@ TEST_CASE("std::format on synthesized unit symbols", "[text][fmt]")
|
||||
SECTION("unknown scaled unit with reference different than the dimension's coherent unit")
|
||||
{
|
||||
// TODO(chogg): Reinstate after format/Magnitude redesign.
|
||||
// constexpr auto mag = units::as_magnitude<units::ratio{2, 3}>();
|
||||
// constexpr auto mag = units::mag<units::ratio{2, 3}>();
|
||||
// CHECK(STD_FMT::format("{}", mass<units::scaled_unit<mag, gram>>(1)) == "1 [2/3 × 10⁻³] kg");
|
||||
// CHECK(STD_FMT::format("{:%Q %Aq}", mass<units::scaled_unit<mag, gram>>(1)) == "1 [2/3 x 10^-3] kg");
|
||||
}
|
||||
|
@@ -66,7 +66,7 @@ void check_same_type_and_value(T actual, U expected)
|
||||
template<ratio R>
|
||||
void check_ratio_round_trip_is_identity()
|
||||
{
|
||||
constexpr Magnitude auto m = as_magnitude<R>();
|
||||
constexpr Magnitude auto m = mag<R>();
|
||||
constexpr ratio round_trip = ratio{
|
||||
get_value<std::intmax_t>(numerator(m)),
|
||||
get_value<std::intmax_t>(denominator(m)),
|
||||
@@ -125,10 +125,10 @@ TEST_CASE("base_power")
|
||||
|
||||
SECTION("product with inverse equals identity")
|
||||
{
|
||||
auto check_product_with_inverse_is_identity = [](auto x) { CHECK(x * pow<-1>(x) == as_magnitude<1>()); };
|
||||
auto check_product_with_inverse_is_identity = [](auto x) { CHECK(x * pow<-1>(x) == mag<1>()); };
|
||||
|
||||
check_product_with_inverse_is_identity(as_magnitude<3>());
|
||||
check_product_with_inverse_is_identity(as_magnitude<ratio{4, 17}>());
|
||||
check_product_with_inverse_is_identity(mag<3>());
|
||||
check_product_with_inverse_is_identity(mag<ratio{4, 17}>());
|
||||
check_product_with_inverse_is_identity(pi_to_the<ratio{-22, 7}>());
|
||||
}
|
||||
|
||||
@@ -144,28 +144,21 @@ TEST_CASE("make_ratio performs prime factorization correctly")
|
||||
{
|
||||
SECTION("Performs prime factorization when denominator is 1")
|
||||
{
|
||||
CHECK(as_magnitude<1>() == magnitude<>{});
|
||||
CHECK(as_magnitude<2>() == magnitude<base_power{2}>{});
|
||||
CHECK(as_magnitude<3>() == magnitude<base_power{3}>{});
|
||||
CHECK(as_magnitude<4>() == magnitude<base_power{2, 2}>{});
|
||||
CHECK(mag<1>() == magnitude<>{});
|
||||
CHECK(mag<2>() == magnitude<base_power{2}>{});
|
||||
CHECK(mag<3>() == magnitude<base_power{3}>{});
|
||||
CHECK(mag<4>() == magnitude<base_power{2, 2}>{});
|
||||
|
||||
CHECK(as_magnitude<792>() == magnitude<base_power{2, 3}, base_power{3, 2}, base_power{11}>{});
|
||||
CHECK(mag<792>() == magnitude<base_power{2, 3}, base_power{3, 2}, base_power{11}>{});
|
||||
}
|
||||
|
||||
SECTION("Supports fractions") { CHECK(as_magnitude<ratio{5, 8}>() == magnitude<base_power{2, -3}, base_power{5}>{}); }
|
||||
|
||||
SECTION("Supports nonzero exp")
|
||||
{
|
||||
constexpr ratio r{3, 1, 2};
|
||||
REQUIRE(r.exp == 2);
|
||||
CHECK(as_magnitude<r>() == as_magnitude<300>());
|
||||
}
|
||||
SECTION("Supports fractions") { CHECK(mag<ratio{5, 8}>() == magnitude<base_power{2, -3}, base_power{5}>{}); }
|
||||
|
||||
SECTION("Can handle prime factor which would be large enough to overflow int")
|
||||
{
|
||||
// This was taken from a case which failed when we used `int` for our base to store prime numbers.
|
||||
// The failure was due to a prime factor which is larger than 2^31.
|
||||
as_magnitude<ratio(16'605'390'666'050, 10'000'000'000'000)>();
|
||||
mag<ratio(16'605'390'666'050, 10'000'000'000'000)>();
|
||||
}
|
||||
|
||||
SECTION("Can bypass computing primes by providing known_first_factor<N>")
|
||||
@@ -176,7 +169,7 @@ TEST_CASE("make_ratio performs prime factorization correctly")
|
||||
// In this case, we test that we can represent the largest prime that fits in a signed 64-bit int. The reason this
|
||||
// test can pass is that we have provided the answer, by specializing the `known_first_factor` variable template
|
||||
// above in this file.
|
||||
as_magnitude<9'223'372'036'854'775'783>();
|
||||
mag<9'223'372'036'854'775'783>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,7 +177,7 @@ TEST_CASE("magnitude converts to numerical value")
|
||||
{
|
||||
SECTION("Positive integer powers of integer bases give integer values")
|
||||
{
|
||||
constexpr auto mag_412 = as_magnitude<412>();
|
||||
constexpr auto mag_412 = mag<412>();
|
||||
check_same_type_and_value(get_value<int>(mag_412), 412);
|
||||
check_same_type_and_value(get_value<std::size_t>(mag_412), std::size_t{412});
|
||||
check_same_type_and_value(get_value<float>(mag_412), 412.0f);
|
||||
@@ -193,7 +186,7 @@ TEST_CASE("magnitude converts to numerical value")
|
||||
|
||||
SECTION("Negative integer powers of integer bases compute correct values")
|
||||
{
|
||||
constexpr auto mag_0p125 = as_magnitude<ratio{1, 8}>();
|
||||
constexpr auto mag_0p125 = mag<ratio{1, 8}>();
|
||||
check_same_type_and_value(get_value<float>(mag_0p125), 0.125f);
|
||||
check_same_type_and_value(get_value<double>(mag_0p125), 0.125);
|
||||
}
|
||||
@@ -226,20 +219,20 @@ TEST_CASE("magnitude converts to numerical value")
|
||||
// Naturally, we cannot actually write a test to verify a compiler error. But any of these can
|
||||
// be uncommented if desired to verify that it breaks the build.
|
||||
|
||||
// get_value<int8_t>(as_magnitude<412>());
|
||||
// get_value<int8_t>(mag<412>());
|
||||
|
||||
// Would work for pow<62>:
|
||||
// get_value<int64_t>(pow<63>(as_magnitude<2>()));
|
||||
// get_value<int64_t>(pow<63>(mag<2>()));
|
||||
|
||||
// Would work for pow<63>:
|
||||
// get_value<uint64_t>(pow<64>(as_magnitude<2>()));
|
||||
// get_value<uint64_t>(pow<64>(mag<2>()));
|
||||
|
||||
get_value<double>(pow<308>(as_magnitude<10>())); // Compiles, correctly.
|
||||
// get_value<double>(pow<309>(as_magnitude<10>()));
|
||||
// get_value<double>(pow<3099>(as_magnitude<10>()));
|
||||
// get_value<double>(pow<3099999>(as_magnitude<10>()));
|
||||
get_value<double>(pow<308>(mag<10>())); // Compiles, correctly.
|
||||
// get_value<double>(pow<309>(mag<10>()));
|
||||
// get_value<double>(pow<3099>(mag<10>()));
|
||||
// get_value<double>(pow<3099999>(mag<10>()));
|
||||
|
||||
auto sqrt_2 = pow<ratio{1, 2}>(as_magnitude<2>());
|
||||
auto sqrt_2 = pow<ratio{1, 2}>(mag<2>());
|
||||
CHECK(!is_integral(sqrt_2));
|
||||
// get_value<int>(sqrt_2);
|
||||
}
|
||||
@@ -249,46 +242,40 @@ TEST_CASE("Equality works for magnitudes")
|
||||
{
|
||||
SECTION("Equivalent ratios are equal")
|
||||
{
|
||||
CHECK(as_magnitude<1>() == as_magnitude<1>());
|
||||
CHECK(as_magnitude<3>() == as_magnitude<3>());
|
||||
CHECK(as_magnitude<ratio{3, 4}>() == as_magnitude<ratio{9, 12}>());
|
||||
CHECK(mag<1>() == mag<1>());
|
||||
CHECK(mag<3>() == mag<3>());
|
||||
CHECK(mag<ratio{3, 4}>() == mag<ratio{9, 12}>());
|
||||
}
|
||||
|
||||
SECTION("Different ratios are unequal")
|
||||
{
|
||||
CHECK(as_magnitude<3>() != as_magnitude<5>());
|
||||
CHECK(as_magnitude<3>() != as_magnitude<ratio{3, 2}>());
|
||||
CHECK(mag<3>() != mag<5>());
|
||||
CHECK(mag<3>() != mag<ratio{3, 2}>());
|
||||
}
|
||||
|
||||
SECTION("Supports constexpr")
|
||||
{
|
||||
constexpr auto eq = (as_magnitude<ratio{4, 5}>() == as_magnitude<ratio{4, 3}>());
|
||||
constexpr auto eq = (mag<ratio{4, 5}>() == mag<ratio{4, 3}>());
|
||||
CHECK(!eq);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Multiplication works for magnitudes")
|
||||
{
|
||||
SECTION("Reciprocals reduce to null magnitude")
|
||||
{
|
||||
CHECK(as_magnitude<ratio{3, 4}>() * as_magnitude<ratio{4, 3}>() == as_magnitude<1>());
|
||||
}
|
||||
SECTION("Reciprocals reduce to null magnitude") { CHECK(mag<ratio{3, 4}>() * mag<ratio{4, 3}>() == mag<1>()); }
|
||||
|
||||
SECTION("Products work as expected")
|
||||
{
|
||||
CHECK(as_magnitude<ratio{4, 5}>() * as_magnitude<ratio{4, 3}>() == as_magnitude<ratio{16, 15}>());
|
||||
}
|
||||
SECTION("Products work as expected") { CHECK(mag<ratio{4, 5}>() * mag<ratio{4, 3}>() == mag<ratio{16, 15}>()); }
|
||||
|
||||
SECTION("Products handle pi correctly")
|
||||
{
|
||||
CHECK(pi_to_the<1>() * as_magnitude<ratio{2, 3}>() * pi_to_the<ratio{-1, 2}>() ==
|
||||
CHECK(pi_to_the<1>() * mag<ratio{2, 3}>() * pi_to_the<ratio{-1, 2}>() ==
|
||||
magnitude<base_power{2}, base_power{3, -1}, base_power<pi_base>{ratio{1, 2}}>{});
|
||||
}
|
||||
|
||||
SECTION("Supports constexpr")
|
||||
{
|
||||
constexpr auto p = as_magnitude<ratio{4, 5}>() * as_magnitude<ratio{4, 3}>();
|
||||
CHECK(p == as_magnitude<ratio{16, 15}>());
|
||||
constexpr auto p = mag<ratio{4, 5}>() * mag<ratio{4, 3}>();
|
||||
CHECK(p == mag<ratio{16, 15}>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,20 +283,20 @@ TEST_CASE("Common Magnitude")
|
||||
{
|
||||
SECTION("Identity for identical magnitudes")
|
||||
{
|
||||
CHECK(common_magnitude(as_magnitude<1>(), as_magnitude<1>()) == as_magnitude<1>());
|
||||
CHECK(common_magnitude(as_magnitude<15>(), as_magnitude<15>()) == as_magnitude<15>());
|
||||
CHECK(common_magnitude(mag<1>(), mag<1>()) == mag<1>());
|
||||
CHECK(common_magnitude(mag<15>(), mag<15>()) == mag<15>());
|
||||
CHECK(common_magnitude(pi_to_the<ratio{3, 4}>(), pi_to_the<ratio{3, 4}>()) == pi_to_the<ratio{3, 4}>());
|
||||
}
|
||||
|
||||
SECTION("Greatest Common Factor for integers")
|
||||
{
|
||||
CHECK(common_magnitude(as_magnitude<24>(), as_magnitude<36>()) == as_magnitude<12>());
|
||||
CHECK(common_magnitude(as_magnitude<24>(), as_magnitude<37>()) == as_magnitude<1>());
|
||||
CHECK(common_magnitude(mag<24>(), mag<36>()) == mag<12>());
|
||||
CHECK(common_magnitude(mag<24>(), mag<37>()) == mag<1>());
|
||||
}
|
||||
|
||||
SECTION("Handles fractions")
|
||||
{
|
||||
CHECK(common_magnitude(as_magnitude<ratio{3, 8}>(), as_magnitude<ratio{5, 6}>()) == as_magnitude<ratio{1, 24}>());
|
||||
CHECK(common_magnitude(mag<ratio{3, 8}>(), mag<ratio{5, 6}>()) == mag<ratio{1, 24}>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,19 +304,16 @@ TEST_CASE("Division works for magnitudes")
|
||||
{
|
||||
SECTION("Dividing anything by itself reduces to null magnitude")
|
||||
{
|
||||
CHECK(as_magnitude<ratio{3, 4}>() / as_magnitude<ratio{3, 4}>() == as_magnitude<1>());
|
||||
CHECK(as_magnitude<15>() / as_magnitude<15>() == as_magnitude<1>());
|
||||
CHECK(mag<ratio{3, 4}>() / mag<ratio{3, 4}>() == mag<1>());
|
||||
CHECK(mag<15>() / mag<15>() == mag<1>());
|
||||
}
|
||||
|
||||
SECTION("Quotients work as expected")
|
||||
{
|
||||
CHECK(as_magnitude<ratio{4, 5}>() / as_magnitude<ratio{4, 3}>() == as_magnitude<ratio{3, 5}>());
|
||||
}
|
||||
SECTION("Quotients work as expected") { CHECK(mag<ratio{4, 5}>() / mag<ratio{4, 3}>() == mag<ratio{3, 5}>()); }
|
||||
|
||||
SECTION("Supports constexpr")
|
||||
{
|
||||
constexpr auto q = as_magnitude<ratio{4, 5}>() / as_magnitude<ratio{4, 3}>();
|
||||
CHECK(q == as_magnitude<ratio{3, 5}>());
|
||||
constexpr auto q = mag<ratio{4, 5}>() / mag<ratio{4, 3}>();
|
||||
CHECK(q == mag<ratio{3, 5}>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,17 +321,17 @@ TEST_CASE("Can raise Magnitudes to rational powers")
|
||||
{
|
||||
SECTION("Anything to the 0 is 1")
|
||||
{
|
||||
CHECK(pow<0>(as_magnitude<1>()) == as_magnitude<1>());
|
||||
CHECK(pow<0>(as_magnitude<123>()) == as_magnitude<1>());
|
||||
CHECK(pow<0>(as_magnitude<ratio{3, 4}>()) == as_magnitude<1>());
|
||||
CHECK(pow<0>(pi_to_the<ratio{-1, 2}>()) == as_magnitude<1>());
|
||||
CHECK(pow<0>(mag<1>()) == mag<1>());
|
||||
CHECK(pow<0>(mag<123>()) == mag<1>());
|
||||
CHECK(pow<0>(mag<ratio{3, 4}>()) == mag<1>());
|
||||
CHECK(pow<0>(pi_to_the<ratio{-1, 2}>()) == mag<1>());
|
||||
}
|
||||
|
||||
SECTION("Anything to the 1 is itself")
|
||||
{
|
||||
CHECK(pow<1>(as_magnitude<1>()) == as_magnitude<1>());
|
||||
CHECK(pow<1>(as_magnitude<123>()) == as_magnitude<123>());
|
||||
CHECK(pow<1>(as_magnitude<ratio{3, 4}>()) == as_magnitude<ratio{3, 4}>());
|
||||
CHECK(pow<1>(mag<1>()) == mag<1>());
|
||||
CHECK(pow<1>(mag<123>()) == mag<123>());
|
||||
CHECK(pow<1>(mag<ratio{3, 4}>()) == mag<ratio{3, 4}>());
|
||||
CHECK(pow<1>(pi_to_the<ratio{-1, 2}>()) == pi_to_the<ratio{-1, 2}>());
|
||||
}
|
||||
|
||||
@@ -366,11 +350,11 @@ TEST_CASE("can distinguish integral, rational, and irrational magnitudes")
|
||||
CHECK(is_rational(m));
|
||||
};
|
||||
check_rational_and_integral(magnitude<>{});
|
||||
check_rational_and_integral(as_magnitude<1>());
|
||||
check_rational_and_integral(as_magnitude<3>());
|
||||
check_rational_and_integral(as_magnitude<8>());
|
||||
check_rational_and_integral(as_magnitude<412>());
|
||||
check_rational_and_integral(as_magnitude<ratio{1, 1}>());
|
||||
check_rational_and_integral(mag<1>());
|
||||
check_rational_and_integral(mag<3>());
|
||||
check_rational_and_integral(mag<8>());
|
||||
check_rational_and_integral(mag<412>());
|
||||
check_rational_and_integral(mag<ratio{1, 1}>());
|
||||
}
|
||||
|
||||
SECTION("Fractional magnitudes are rational, but not integral")
|
||||
@@ -379,8 +363,8 @@ TEST_CASE("can distinguish integral, rational, and irrational magnitudes")
|
||||
CHECK(!is_integral(m));
|
||||
CHECK(is_rational(m));
|
||||
};
|
||||
check_rational_but_not_integral(as_magnitude<ratio{1, 2}>());
|
||||
check_rational_but_not_integral(as_magnitude<ratio{5, 8}>());
|
||||
check_rational_but_not_integral(mag<ratio{1, 2}>());
|
||||
check_rational_but_not_integral(mag<ratio{5, 8}>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -397,17 +381,17 @@ TEST_CASE("Constructing ratio from rational magnitude")
|
||||
|
||||
SECTION("Rational magnitude converts to ratio")
|
||||
{
|
||||
constexpr ratio r = as_ratio(as_magnitude<ratio{22, 7}>());
|
||||
constexpr ratio r = as_ratio(mag<ratio{22, 7}>());
|
||||
CHECK(r == ratio{22, 7});
|
||||
}
|
||||
|
||||
SECTION("Irrational magnitude does not convert to ratio")
|
||||
{
|
||||
// The following code should not compile.
|
||||
// as_ratio(pow<ratio{1, 2}>(as_magnitude<2>()));
|
||||
// as_ratio(pow<ratio{1, 2}>(mag<2>()));
|
||||
|
||||
// The following code should not compile.
|
||||
// as_ratio(as_magnitude<180>() / pi_to_the<1>());
|
||||
// as_ratio(mag<180>() / pi_to_the<1>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -614,26 +598,26 @@ TEST_CASE("extract_power_of_10")
|
||||
{
|
||||
SECTION("Picks out positive powers")
|
||||
{
|
||||
CHECK(extract_power_of_10(as_magnitude<10>()) == 1);
|
||||
CHECK(extract_power_of_10(as_magnitude<20>()) == 1);
|
||||
CHECK(extract_power_of_10(as_magnitude<40>()) == 1);
|
||||
CHECK(extract_power_of_10(as_magnitude<50>()) == 1);
|
||||
CHECK(extract_power_of_10(as_magnitude<100>()) == 2);
|
||||
CHECK(extract_power_of_10(mag<10>()) == 1);
|
||||
CHECK(extract_power_of_10(mag<20>()) == 1);
|
||||
CHECK(extract_power_of_10(mag<40>()) == 1);
|
||||
CHECK(extract_power_of_10(mag<50>()) == 1);
|
||||
CHECK(extract_power_of_10(mag<100>()) == 2);
|
||||
}
|
||||
|
||||
SECTION("Picks out negative powers")
|
||||
{
|
||||
constexpr auto ONE = as_magnitude<1>();
|
||||
CHECK(extract_power_of_10(ONE / as_magnitude<10>()) == -1);
|
||||
CHECK(extract_power_of_10(ONE / as_magnitude<20>()) == -1);
|
||||
CHECK(extract_power_of_10(ONE / as_magnitude<40>()) == -1);
|
||||
CHECK(extract_power_of_10(ONE / as_magnitude<50>()) == -1);
|
||||
CHECK(extract_power_of_10(ONE / as_magnitude<100>()) == -2);
|
||||
constexpr auto ONE = mag<1>();
|
||||
CHECK(extract_power_of_10(ONE / mag<10>()) == -1);
|
||||
CHECK(extract_power_of_10(ONE / mag<20>()) == -1);
|
||||
CHECK(extract_power_of_10(ONE / mag<40>()) == -1);
|
||||
CHECK(extract_power_of_10(ONE / mag<50>()) == -1);
|
||||
CHECK(extract_power_of_10(ONE / mag<100>()) == -2);
|
||||
}
|
||||
|
||||
SECTION("Zero if signs disagree") { CHECK(extract_power_of_10(as_magnitude<2>() / as_magnitude<5>()) == 0); }
|
||||
SECTION("Zero if signs disagree") { CHECK(extract_power_of_10(mag<2>() / mag<5>()) == 0); }
|
||||
|
||||
SECTION("Handles rational powers") { CHECK(extract_power_of_10(sqrt(as_magnitude<1000>())) == 1); }
|
||||
SECTION("Handles rational powers") { CHECK(extract_power_of_10(sqrt(mag<1000>())) == 1); }
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@@ -22,6 +22,7 @@
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
#include <units/isq/si/area.h>
|
||||
#include <units/isq/si/cgs/length.h>
|
||||
#include <units/isq/si/length.h>
|
||||
#include <units/isq/si/time.h>
|
||||
#include <units/isq/si/volume.h>
|
||||
@@ -30,7 +31,7 @@
|
||||
|
||||
using namespace units;
|
||||
using namespace units::isq;
|
||||
using namespace units::isq::si;
|
||||
using namespace units::isq::si::literals;
|
||||
|
||||
// classical
|
||||
|
||||
@@ -186,10 +187,10 @@ TEST_CASE("ceil functions", "[ceil]")
|
||||
{
|
||||
REQUIRE(ceil<si::second>(1999._q_ms) == 2_q_s);
|
||||
}
|
||||
// TODO does not work, probably due to a bug in fpow10() see #311
|
||||
// SECTION ("ceil -1000. milliseconds with target unit second should be -1 second") {
|
||||
// REQUIRE(ceil<si::second>(-1000._q_ms) == -1_q_s);
|
||||
// }
|
||||
SECTION("ceil -1000. milliseconds with target unit second should be -1 second")
|
||||
{
|
||||
REQUIRE(ceil<si::second>(-1000._q_ms) == -1_q_s);
|
||||
}
|
||||
SECTION("ceil -999. milliseconds with target unit second should be 0 seconds")
|
||||
{
|
||||
REQUIRE(ceil<si::second>(-999._q_ms) == 0_q_s);
|
||||
@@ -363,3 +364,24 @@ TEMPLATE_PRODUCT_TEST_CASE_SIG("detail::iroot<N>()", "[math][pow][iroot]", (std:
|
||||
|
||||
ROOT_TEST_CASE(CompileRoot)
|
||||
ROOT_TEST_CASE(RuntimeRoot)
|
||||
|
||||
TEST_CASE("hypot functions", "[hypot]")
|
||||
{
|
||||
using namespace units::aliases::isq::si;
|
||||
|
||||
SECTION("hypot should work on the same quantities")
|
||||
{
|
||||
REQUIRE(hypot(km<>(3.), km<>(4.)) == km<>(5.));
|
||||
REQUIRE(hypot(km<>(2.), km<>(3.), km<>(6.)) == km<>(7.));
|
||||
}
|
||||
SECTION("hypot should work with different units of the same dimension")
|
||||
{
|
||||
REQUIRE(hypot(km<>(3.), m<>(4000.)) == km<>(5.));
|
||||
REQUIRE(hypot(km<>(2.), m<>(3000.), km<>(6.)) == km<>(7.));
|
||||
}
|
||||
SECTION("hypot should work with different but equivalent dimensions")
|
||||
{
|
||||
REQUIRE(hypot(km<>(3.), cgs::length::cm<>(400'000.)) == km<>(5.));
|
||||
REQUIRE(hypot(km<>(2.), cgs::length::cm<>(300'000.), km<>(6.)) == km<>(7.));
|
||||
}
|
||||
}
|
||||
|
@@ -58,7 +58,8 @@ static_assert(!Area<si::time<si::second>>);
|
||||
static_assert(Volume<si::volume<si::cubic_metre>>);
|
||||
static_assert(!Volume<si::area<si::square_metre>>);
|
||||
#if UNITS_DOWNCAST_MODE == 0
|
||||
static_assert(Volume<quantity<unknown_dimension<exponent<si::dim_length, 3>>, unknown_coherent_unit>>);
|
||||
static_assert(
|
||||
Volume<quantity<unknown_dimension<exponent<si::dim_length, 3>>, unknown_coherent_unit<exponent<si::dim_length, 3>>>>);
|
||||
#endif
|
||||
|
||||
static_assert(Speed<si::speed<si::metre_per_second>>);
|
||||
@@ -68,21 +69,23 @@ static_assert(Acceleration<si::acceleration<si::metre_per_second_sq>>);
|
||||
static_assert(!Acceleration<si::time<si::second>>);
|
||||
#if UNITS_DOWNCAST_MODE == 0
|
||||
static_assert(Acceleration<quantity<unknown_dimension<exponent<si::dim_length, 1>, exponent<si::dim_time, -2>>,
|
||||
unknown_coherent_unit>>);
|
||||
unknown_coherent_unit<exponent<si::dim_length, 1>, exponent<si::dim_time, -2>>>>);
|
||||
#endif
|
||||
|
||||
static_assert(Force<si::force<si::newton>>);
|
||||
static_assert(!Force<si::time<si::second>>);
|
||||
#if UNITS_DOWNCAST_MODE == 0
|
||||
// static_assert(Force<quantity<unknown_dimension<exponent<si::dim_length, 1>, exponent<si::dim_time, -2>,
|
||||
// exponent<si::dim_mass, 1>>, unknown_coherent_unit>>);
|
||||
// exponent<si::dim_mass, 1>>, unknown_coherent_unit<exponent<si::dim_length, 1>,
|
||||
// exponent<si::dim_time, -2>>>);
|
||||
#endif
|
||||
|
||||
static_assert(Energy<si::energy<si::joule>>);
|
||||
static_assert(!Energy<si::time<si::second>>);
|
||||
#if UNITS_DOWNCAST_MODE == 0
|
||||
// static_assert(Energy<quantity<unknown_dimension<exponent<si::dim_mass, 1>, exponent<si::dim_length, 2>,
|
||||
// exponent<si::dim_time, -3>>, unknown_coherent_unit>>);
|
||||
// exponent<si::dim_time, -3>>, unknown_coherent_unit<exponent<si::dim_mass, 1>,
|
||||
// exponent<si::dim_length, 2>>>);
|
||||
#endif
|
||||
|
||||
static_assert(Power<si::power<si::watt>>);
|
||||
|
@@ -456,9 +456,9 @@ concept invalid_compound_assignments =
|
||||
requires !requires { w *= m; };
|
||||
requires !requires { w /= m; };
|
||||
requires !requires { w %= m; };
|
||||
requires !requires { w *= quantity_kind<downcast_kind<Width, dim_one>, scaled_unit<as_magnitude<1000>(), one>, int>{1}; };
|
||||
requires !requires { w /= quantity_kind<downcast_kind<Width, dim_one>, scaled_unit<as_magnitude<1000>(), one>, int>{1}; };
|
||||
requires !requires { w %= quantity_kind<downcast_kind<Width, dim_one>, scaled_unit<as_magnitude<1000>(), one>, int>{1}; };
|
||||
requires !requires { w *= quantity_kind<downcast_kind<Width, dim_one>, scaled_unit<mag<1000>(), one>, int>{1}; };
|
||||
requires !requires { w /= quantity_kind<downcast_kind<Width, dim_one>, scaled_unit<mag<1000>(), one>, int>{1}; };
|
||||
requires !requires { w %= quantity_kind<downcast_kind<Width, dim_one>, scaled_unit<mag<1000>(), one>, int>{1}; };
|
||||
requires !requires { w %= 1.0; };
|
||||
requires !requires { w %= quantity(1.0); };
|
||||
requires !requires { w %= 1.0 * (w / w); };
|
||||
|
@@ -287,7 +287,7 @@ static_assert(get_length_derived_quantity() == 1_q_m);
|
||||
// CTAD
|
||||
/////////
|
||||
|
||||
#if UNITS_COMP_GCC >= 11 || UNITS_COMP_CLANG > 15
|
||||
#if UNITS_COMP_GCC >= 11 || UNITS_COMP_CLANG > 16
|
||||
static_assert(std::is_same_v<decltype(aliases::isq::si::m(123))::rep, int>);
|
||||
static_assert(std::is_same_v<decltype(aliases::isq::si::m(123.))::rep, double>);
|
||||
static_assert(
|
||||
@@ -498,7 +498,7 @@ static_assert(compare<decltype(1_q_m / 1_q_m), dimensionless<one, std::int64_t>>
|
||||
static_assert(compare<decltype(1 / 1_q_s), frequency<hertz, std::int64_t>>);
|
||||
static_assert(compare<decltype(quantity{1} / 1_q_s), frequency<hertz, std::int64_t>>);
|
||||
static_assert(compare<decltype(dimensionless<percent, std::int64_t>(1) / 1_q_s),
|
||||
frequency<scaled_unit<as_magnitude<ratio(1, 100)>(), hertz>, std::int64_t>>);
|
||||
frequency<scaled_unit<mag<ratio(1, 100)>(), hertz>, std::int64_t>>);
|
||||
|
||||
static_assert(is_same_v<decltype((std::uint8_t(0) * m + std::uint8_t(0) * m).number()), int&&>);
|
||||
static_assert(is_same_v<decltype((std::uint8_t(0) * m - std::uint8_t(0) * m).number()), int&&>);
|
||||
@@ -529,7 +529,7 @@ static_assert(compare<decltype(1_q_m / 1._q_m), dimensionless<one, long double>>
|
||||
static_assert(compare<decltype(1 / 1._q_s), frequency<hertz, long double>>);
|
||||
static_assert(compare<decltype(quantity{1} / 1._q_s), frequency<hertz, long double>>);
|
||||
static_assert(compare<decltype(dimensionless<percent, std::int64_t>(1) / 1._q_s),
|
||||
frequency<scaled_unit<as_magnitude<ratio(1, 100)>(), hertz>, long double>>);
|
||||
frequency<scaled_unit<mag<ratio(1, 100)>(), hertz>, long double>>);
|
||||
static_assert(compare<decltype(1_q_m % short(1)), length<metre, std::int64_t>>);
|
||||
static_assert(compare<decltype(1_q_m % quantity{short(1)}), length<metre, std::int64_t>>);
|
||||
static_assert(compare<decltype(1_q_m % dimensionless<percent, short>(1)), length<metre, std::int64_t>>);
|
||||
@@ -551,7 +551,7 @@ static_assert(compare<decltype(1._q_m / 1_q_m), dimensionless<one, long double>>
|
||||
static_assert(compare<decltype(1.L / 1_q_s), frequency<hertz, long double>>);
|
||||
static_assert(compare<decltype(quantity{1.L} / 1_q_s), frequency<hertz, long double>>);
|
||||
static_assert(compare<decltype(dimensionless<percent, long double>(1) / 1_q_s),
|
||||
frequency<scaled_unit<as_magnitude<ratio(1, 100)>(), hertz>, long double>>);
|
||||
frequency<scaled_unit<mag<ratio(1, 100)>(), hertz>, long double>>);
|
||||
|
||||
// different units
|
||||
static_assert(compare<decltype(1_q_m + 1_q_km), length<metre, std::int64_t>>);
|
||||
@@ -579,25 +579,28 @@ static_assert(is_same_v<decltype(1_q_km % 1_q_m), length<kilometre, std::int64_t
|
||||
|
||||
// different dimensions
|
||||
static_assert(compare<decltype(1_q_m_per_s * 1_q_s), length<metre, std::int64_t>>);
|
||||
static_assert(compare<decltype(1_q_m_per_s * 1_q_h), length<scaled_unit<mag<3600>(), metre>, std::int64_t>>);
|
||||
static_assert(
|
||||
compare<decltype(1_q_m_per_s * 1_q_h), length<scaled_unit<as_magnitude<ratio(36, 1, 2)>(), metre>, std::int64_t>>);
|
||||
static_assert(
|
||||
compare<decltype(1_q_m * 1_q_min), quantity<unknown_dimension<exponent<dim_length, 1>, exponent<dim_time, 1>>,
|
||||
scaled_unit<as_magnitude<60>(), unknown_coherent_unit>, std::int64_t>>);
|
||||
compare<decltype(1_q_m * 1_q_min),
|
||||
quantity<unknown_dimension<exponent<dim_length, 1>, exponent<dim_time, 1>>,
|
||||
scaled_unit<mag<60>(), unknown_coherent_unit<exponent<dim_length, 1>, exponent<dim_time, 1>>>,
|
||||
std::int64_t>>);
|
||||
static_assert(compare<decltype(1_q_s * 1_q_Hz), dimensionless<one, std::int64_t>>);
|
||||
static_assert(
|
||||
compare<decltype(1 / 1_q_min), frequency<scaled_unit<as_magnitude<ratio(1, 60)>(), hertz>, std::int64_t>>);
|
||||
static_assert(compare<decltype(1 / 1_q_min), frequency<scaled_unit<mag<ratio(1, 60)>(), hertz>, std::int64_t>>);
|
||||
static_assert(compare<decltype(1 / 1_q_Hz), isq::si::time<second, std::int64_t>>);
|
||||
static_assert(compare<decltype(1 / 1_q_km),
|
||||
static_assert(
|
||||
compare<decltype(1 / 1_q_km),
|
||||
quantity<unknown_dimension<exponent<dim_length, -1>>,
|
||||
scaled_unit<as_magnitude<ratio(1, 1, -3)>(), unknown_coherent_unit>, std::int64_t>>);
|
||||
static_assert(compare<decltype(1_q_km / 1_q_m), dimensionless<scaled_unit<as_magnitude<1000>(), one>, std::int64_t>>);
|
||||
scaled_unit<mag<ratio(1, 1000)>(), unknown_coherent_unit<exponent<dim_length, -1>>>, std::int64_t>>);
|
||||
static_assert(compare<decltype(1_q_km / 1_q_m), dimensionless<scaled_unit<mag<1000>(), one>, std::int64_t>>);
|
||||
static_assert(compare<decltype(1_q_m / 1_q_s), speed<metre_per_second, std::int64_t>>);
|
||||
static_assert(
|
||||
compare<decltype(1_q_m / 1_q_min), speed<scaled_unit<as_magnitude<ratio(1, 60)>(), metre_per_second>, std::int64_t>>);
|
||||
compare<decltype(1_q_m / 1_q_min), speed<scaled_unit<mag<ratio(1, 60)>(), metre_per_second>, std::int64_t>>);
|
||||
static_assert(
|
||||
compare<decltype(1_q_min / 1_q_m), quantity<unknown_dimension<exponent<dim_length, -1>, exponent<dim_time, 1>>,
|
||||
scaled_unit<as_magnitude<60>(), unknown_coherent_unit>, std::int64_t>>);
|
||||
compare<decltype(1_q_min / 1_q_m),
|
||||
quantity<unknown_dimension<exponent<dim_length, -1>, exponent<dim_time, 1>>,
|
||||
scaled_unit<mag<60>(), unknown_coherent_unit<exponent<dim_length, -1>, exponent<dim_time, 1>>>,
|
||||
std::int64_t>>);
|
||||
|
||||
static_assert((1_q_m + 1_q_m).number() == 2);
|
||||
static_assert((1_q_m + 1_q_km).number() == 1001);
|
||||
@@ -885,11 +888,13 @@ static_assert(!is_same_v<decltype(quantity_cast<litre>(2_q_dm3)), volume<cubic_d
|
||||
|
||||
#if UNITS_DOWNCAST_MODE == 0
|
||||
|
||||
static_assert(is_same_v<decltype(10_q_m / 5_q_s),
|
||||
quantity<unknown_dimension<units::exponent<dim_length, 1>, units::exponent<dim_time, -1>>,
|
||||
scaled_unit<as_magnitude<1>(), unknown_coherent_unit>, std::int64_t>>);
|
||||
static_assert(
|
||||
is_same_v<decltype(1_q_mm + 1_q_km), length<scaled_unit<as_magnitude<ratio(1, 1, -3)>(), metre>, std::int64_t>>);
|
||||
is_same_v<decltype(10_q_m / 5_q_s),
|
||||
quantity<unknown_dimension<units::exponent<dim_length, 1>, units::exponent<dim_time, -1>>,
|
||||
scaled_unit<mag<1>(),
|
||||
unknown_coherent_unit<units::exponent<dim_length, 1>, units::exponent<dim_time, -1>>>,
|
||||
std::int64_t>>);
|
||||
static_assert(is_same_v<decltype(1_q_mm + 1_q_km), length<scaled_unit<mag<ratio(1, 1000)>(), metre>, std::int64_t>>);
|
||||
|
||||
#else
|
||||
|
||||
@@ -919,8 +924,7 @@ static_assert(same(quotient_remainder_theorem(3'000 * m, 400), 3'000 * m));
|
||||
static_assert(comp(quotient_remainder_theorem(3'000 * m, quantity(400)), 3'000 * m));
|
||||
static_assert(comp(quotient_remainder_theorem(3 * km, quantity(400)), 3 * km));
|
||||
static_assert(comp(quotient_remainder_theorem(3 * km, quantity(2)), 3 * km));
|
||||
static_assert(
|
||||
comp(quotient_remainder_theorem(3 * km, dimensionless<scaled_unit<as_magnitude<ratio(1, 1000)>(), one>, int>(400)),
|
||||
static_assert(comp(quotient_remainder_theorem(3 * km, dimensionless<scaled_unit<mag<ratio(1, 1000)>(), one>, int>(400)),
|
||||
3 * km));
|
||||
|
||||
} // namespace
|
||||
|
@@ -28,11 +28,6 @@ using namespace units;
|
||||
|
||||
static_assert(ratio(2, 4) == ratio(1, 2));
|
||||
|
||||
// basic exponents tests
|
||||
static_assert(ratio(2, 40, 1) == ratio(1, 20, 1));
|
||||
static_assert(ratio(20, 4, -1) == ratio(10, 2, -1));
|
||||
static_assert(ratio(200, 5) == ratio(20'000, 50, -1));
|
||||
|
||||
static_assert(ratio(1) * ratio(3, 8) == ratio(3, 8));
|
||||
static_assert(ratio(3, 8) * ratio(1) == ratio(3, 8));
|
||||
static_assert(ratio(4) * ratio(1, 8) == ratio(1, 2));
|
||||
@@ -45,21 +40,12 @@ static_assert(-ratio(3, 8) == ratio(-3, 8));
|
||||
|
||||
// ratio addition
|
||||
static_assert(ratio(1, 2) + ratio(1, 3) == ratio(5, 6));
|
||||
static_assert(ratio(1, 3, 2) + ratio(11, 6) == ratio(211, 6)); // 100/3 + 11/6
|
||||
|
||||
// multiply with exponents
|
||||
static_assert(ratio(1, 8, 2) * ratio(2, 1, 4) == ratio(1, 4, 6));
|
||||
static_assert(ratio(1, 2, -4) * ratio(8, 1, 3) == ratio(4, 1, -1));
|
||||
|
||||
static_assert(ratio(4) / ratio(2) == ratio(2));
|
||||
static_assert(ratio(2) / ratio(8) == ratio(1, 4));
|
||||
static_assert(ratio(1, 8) / ratio(2) == ratio(1, 16));
|
||||
static_assert(ratio(6) / ratio(3) == ratio(2));
|
||||
|
||||
// divide with exponents
|
||||
static_assert(ratio(1, 8, -6) / ratio(2, 1, -8) == ratio(1, 16, 2));
|
||||
static_assert(ratio(6, 1, 4) / ratio(3) == ratio(2, 1, 4));
|
||||
|
||||
static_assert(pow<0>(ratio(2)) == ratio(1));
|
||||
static_assert(pow<1>(ratio(2)) == ratio(2));
|
||||
static_assert(pow<2>(ratio(2)) == ratio(4));
|
||||
@@ -69,27 +55,6 @@ static_assert(pow<1>(ratio(1, 2)) == ratio(1, 2));
|
||||
static_assert(pow<2>(ratio(1, 2)) == ratio(1, 4));
|
||||
static_assert(pow<3>(ratio(1, 2)) == ratio(1, 8));
|
||||
|
||||
// pow with exponents
|
||||
static_assert(pow<2>(ratio(1, 2, 3)) == ratio(1, 4, 6));
|
||||
static_assert(pow<4, 2>(ratio(1, 2, 3)) == ratio(1, 4, 6));
|
||||
static_assert(pow<3>(ratio(1, 2, -6)) == ratio(1, 8, -18));
|
||||
|
||||
static_assert(sqrt(ratio(9)) == ratio(3));
|
||||
static_assert(cbrt(ratio(27)) == ratio(3));
|
||||
static_assert(sqrt(ratio(4)) == ratio(2));
|
||||
static_assert(cbrt(ratio(8)) == ratio(2));
|
||||
static_assert(sqrt(ratio(1)) == ratio(1));
|
||||
static_assert(cbrt(ratio(1)) == ratio(1));
|
||||
static_assert(sqrt(ratio(0)) == ratio(0));
|
||||
static_assert(cbrt(ratio(0)) == ratio(0));
|
||||
static_assert(sqrt(ratio(1, 4)) == ratio(1, 2));
|
||||
static_assert(cbrt(ratio(1, 8)) == ratio(1, 2));
|
||||
|
||||
// sqrt with exponents
|
||||
static_assert(sqrt(ratio(9, 1, 2)) == ratio(3, 1, 1));
|
||||
static_assert(cbrt(ratio(27, 1, 3)) == ratio(3, 1, 1));
|
||||
static_assert(cbrt(ratio(27, 1, 2)) == ratio(13, 1, 0));
|
||||
|
||||
// common_ratio
|
||||
static_assert(common_ratio(ratio(1), ratio(1000)) == ratio(1));
|
||||
static_assert(common_ratio(ratio(1000), ratio(1)) == ratio(1));
|
||||
@@ -98,20 +63,9 @@ static_assert(common_ratio(ratio(1, 1000), ratio(1)) == ratio(1, 1000));
|
||||
static_assert(common_ratio(ratio(100, 1), ratio(10, 1)) == ratio(10, 1));
|
||||
static_assert(common_ratio(ratio(100, 1), ratio(1, 10)) == ratio(1, 10));
|
||||
|
||||
// common ratio with exponents
|
||||
static_assert(common_ratio(ratio(1), ratio(1, 1, 3)) == ratio(1));
|
||||
static_assert(common_ratio(ratio(10, 1, -1), ratio(1, 1, -3)) == ratio(1, 1, -3));
|
||||
|
||||
// numerator and denominator
|
||||
static_assert(numerator(ratio(3, 4)) == 3);
|
||||
static_assert(numerator(ratio(3, 7, 2)) == 300);
|
||||
static_assert(denominator(ratio(3, 4)) == 4);
|
||||
static_assert(denominator(ratio(3, 7, -2)) == 700);
|
||||
|
||||
// comparison
|
||||
static_assert((ratio(3, 4) <=> ratio(6, 8)) == (0 <=> 0));
|
||||
static_assert((ratio(3, 4) <=> ratio(-3, 4)) == (0 <=> -1));
|
||||
static_assert((ratio(-3, 4) <=> ratio(3, -4)) == (0 <=> 0));
|
||||
static_assert((ratio(1, 1, 1) <=> ratio(10)) == (0 <=> 0));
|
||||
|
||||
} // namespace
|
||||
|
@@ -116,7 +116,7 @@ static_assert(si::length<si::metre>(1) + quantity_cast<si::length<si::metre>>(10
|
||||
static_assert(100_q_cm + quantity_cast<si::cgs::length<si::cgs::centimetre>>(si::length<si::metre>(1)) == 200_q_cm);
|
||||
static_assert(quantity_cast<si::cgs::length<si::cgs::centimetre>>(si::length<si::metre>(1)) + 100_q_cm == 200_q_cm);
|
||||
|
||||
// substraction
|
||||
// subtraction
|
||||
|
||||
static_assert(500_q_cm - si::length<si::metre>(1) == si::length<si::metre>(4));
|
||||
static_assert(si::length<si::metre>(5) - 100_q_cm == si::length<si::metre>(4));
|
||||
@@ -127,8 +127,8 @@ static_assert(quantity_cast<si::cgs::length<si::cgs::centimetre>>(si::length<si:
|
||||
|
||||
// multiplication
|
||||
|
||||
// static_assert(200_q_cm * si::length<si::metre>(2) == si::area<si::square_metre>(4)); // TODO Add support for
|
||||
// comparing of an unknown_dimension
|
||||
// TODO Add support for comparing of an unknown_dimension
|
||||
// static_assert(200._q_cm * si::length<si::metre>(2) == si::area<si::square_metre>(4));
|
||||
|
||||
static_assert(quantity_cast<si::dim_length>(200._q_cm) * si::length<si::metre>(2) == si::area<si::square_metre>(4));
|
||||
static_assert(200._q_cm * quantity_cast<si::cgs::dim_length>(si::length<si::metre>(2)) == 40'000_q_cm2);
|
||||
@@ -142,14 +142,32 @@ static_assert(200._q_cm * quantity_cast<si::cgs::dim_length>(si::length<si::metr
|
||||
|
||||
// division
|
||||
|
||||
// static_assert(si::area<si::square_metre>(4) / 200_q_cm == si::length<si::metre>(2)); // TODO Add support for
|
||||
// comparing of an unknown_dimension
|
||||
// TODO Add support for comparing of an unknown_dimension
|
||||
// static_assert(si::area<si::square_metre>(4) / 200_q_cm == si::length<si::metre>(2));
|
||||
// static_assert(400._q_cm / si::length<si::metre>(2) == 2);
|
||||
|
||||
static_assert(si::area<si::square_metre>(4) / quantity_cast<si::length<si::metre>>(200_q_cm) ==
|
||||
si::length<si::metre>(2));
|
||||
static_assert(quantity_cast<si::cgs::area<si::cgs::square_centimetre>>(si::area<si::square_metre>(4)) / 200._q_cm ==
|
||||
200_q_cm);
|
||||
|
||||
static_assert(si::cgs::length<si::cgs::centimetre>(50) == si::length<si::centimetre>(50));
|
||||
static_assert(si::cgs::mass<si::cgs::gram>(50) == si::mass<si::gram>(50));
|
||||
|
||||
static_assert(1 / si::cgs::length<si::cgs::centimetre>(50) == 1 / si::length<si::centimetre>(50));
|
||||
static_assert(1 / si::cgs::length<si::metre>(50) == 1 / si::length<si::metre>(50));
|
||||
|
||||
static_assert(1 / si::cgs::mass<si::cgs::gram>(50) == 1 / si::mass<si::gram>(50));
|
||||
static_assert(1 / si::cgs::mass<si::kilogram>(50) == 1 / si::mass<si::kilogram>(50));
|
||||
|
||||
static_assert(si::cgs::length<si::cgs::centimetre>(50) * si::cgs::mass<si::cgs::gram>(50) ==
|
||||
si::length<si::centimetre>(50) * si::mass<si::gram>(50));
|
||||
static_assert(si::cgs::length<si::metre>(50) * si::cgs::mass<si::kilogram>(50) ==
|
||||
si::length<si::metre>(50) * si::mass<si::kilogram>(50));
|
||||
|
||||
static_assert(si::cgs::length<si::cgs::centimetre>(50) / si::cgs::mass<si::cgs::gram>(50) ==
|
||||
si::length<si::centimetre>(50) / si::mass<si::gram>(50));
|
||||
|
||||
} // namespace cgs_test
|
||||
|
||||
} // namespace
|
||||
|
@@ -157,8 +157,8 @@ static_assert(quantity_cast<si::fps::length<si::fps::foot>>(si::length<si::metre
|
||||
|
||||
// multiplication
|
||||
|
||||
// static_assert(2 * ft * si::length<si::metre>(2) == si::area<si::square_metre>(1.2192)); // TODO Add support for
|
||||
// comparing of an unknown_dimension
|
||||
// TODO Add support for comparing of an unknown_dimension
|
||||
// static_assert(2 * ft * si::length<si::metre>(2) == si::area<si::square_metre>(1.2192));
|
||||
static_assert(quantity_cast<si::length<si::metre>>(2. * ft) * si::length<si::metre>(2) ==
|
||||
si::area<si::square_metre>(1.2192));
|
||||
static_assert(quantity_cast<si::length<si::metre>>(2. * ft) * si::length<si::metre>(0.6096) ==
|
||||
@@ -167,8 +167,10 @@ static_assert(2. * ft * quantity_cast<si::fps::length<si::fps::foot>>(si::length
|
||||
|
||||
// division
|
||||
|
||||
// static_assert(si::area<si::square_metre>(4) / 200_q_cm == si::length<si::metre>(2)); // TODO Add support for
|
||||
// comparing of an unknown_dimension
|
||||
// TODO Add support for comparing of an unknown_dimension
|
||||
// static_assert(si::area<si::square_metre>(4) / 200_q_cm == si::length<si::metre>(2));
|
||||
// static_assert(400._q_cm / si::length<si::metre>(2) == 2);
|
||||
|
||||
static_assert(si::area<si::square_metre>(1.48644864) / quantity_cast<si::length<si::metre>>(4 * ft) ==
|
||||
si::length<si::metre>(1.2192)); // 16 ft2 / 4 ft = 4 ft
|
||||
static_assert(quantity_cast<si::fps::area<si::fps::square_foot>>(si::area<si::square_metre>(1.48644864)) / (4. * ft) ==
|
||||
|
@@ -43,7 +43,7 @@ static_assert(1_q_au == 149'597'870'700_q_m);
|
||||
static_assert(1_q_km + 1_q_m == 1001_q_m);
|
||||
static_assert(10_q_km / 5_q_km == 2);
|
||||
static_assert(10_q_km / 5_q_km < 3);
|
||||
static_assert(100_q_mm / 5_q_cm == dimensionless<scaled_unit<as_magnitude<ratio(1, 10)>(), one>>(20));
|
||||
static_assert(100_q_mm / 5_q_cm == dimensionless<scaled_unit<mag<ratio(1, 10)>(), one>>(20));
|
||||
static_assert(100_q_mm / 5_q_cm == dimensionless<one>(2));
|
||||
static_assert(10_q_km / 2 == 5_q_km);
|
||||
|
||||
@@ -107,7 +107,7 @@ static_assert(1000 / 1_q_s == 1_q_kHz);
|
||||
static_assert(1 / 1_q_ms == 1_q_kHz);
|
||||
static_assert(3.2_q_GHz == 3'200'000'000_q_Hz);
|
||||
static_assert((10_q_Hz * 1_q_min).number() == 10);
|
||||
static_assert(10_q_Hz * 1_q_min == dimensionless<scaled_unit<as_magnitude<60>(), one>>(10));
|
||||
static_assert(10_q_Hz * 1_q_min == dimensionless<scaled_unit<mag<60>(), one>>(10));
|
||||
static_assert(10_q_Hz * 1_q_min == dimensionless<one>(600));
|
||||
static_assert(2 / 1_q_Hz == 2_q_s);
|
||||
|
||||
|
@@ -36,12 +36,12 @@ using namespace units::isq;
|
||||
struct metre : named_unit<metre, "m"> {};
|
||||
struct centimetre : prefixed_unit<centimetre, si::centi, metre> {};
|
||||
struct kilometre : prefixed_unit<kilometre, si::kilo, metre> {};
|
||||
struct yard : named_scaled_unit<yard, "yd", as_magnitude<ratio(9'144, 1, -4)>(), metre> {};
|
||||
struct foot : named_scaled_unit<foot, "ft", as_magnitude<ratio(1, 3)>(), yard> {};
|
||||
struct yard : named_scaled_unit<yard, "yd", mag<ratio{9'144, 10'000}>(), metre> {};
|
||||
struct foot : named_scaled_unit<foot, "ft", mag<ratio(1, 3)>(), yard> {};
|
||||
struct dim_length : base_dimension<"length", metre> {};
|
||||
|
||||
struct second : named_unit<second, "s"> {};
|
||||
struct hour : named_scaled_unit<hour, "h", as_magnitude<ratio(36, 1, 2)>(), second> {};
|
||||
struct hour : named_scaled_unit<hour, "h", mag<3600>(), second> {};
|
||||
struct dim_time : base_dimension<"time", second> {};
|
||||
|
||||
struct kelvin : named_unit<kelvin, "K"> {};
|
||||
@@ -59,10 +59,10 @@ struct kilometre_per_hour : derived_scaled_unit<kilometre_per_hour, dim_speed, k
|
||||
|
||||
static_assert(equivalent<metre::named_unit, metre>);
|
||||
static_assert(equivalent<metre::scaled_unit, metre>);
|
||||
static_assert(compare<downcast<scaled_unit<as_magnitude<1>(), metre>>, metre>);
|
||||
static_assert(compare<downcast<scaled_unit<as_magnitude<ratio(1, 1, -2)>(), metre>>, centimetre>);
|
||||
static_assert(compare<downcast<scaled_unit<mag<1>(), metre>>, metre>);
|
||||
static_assert(compare<downcast<scaled_unit<mag<ratio(1, 100)>(), metre>>, centimetre>);
|
||||
static_assert(compare<downcast<scaled_unit<yard::mag, metre>>, yard>);
|
||||
static_assert(compare<downcast<scaled_unit<yard::mag / as_magnitude<3>(), metre>>, foot>);
|
||||
static_assert(compare<downcast<scaled_unit<yard::mag / mag<3>(), metre>>, foot>);
|
||||
static_assert(compare<downcast<scaled_unit<kilometre::mag / hour::mag, metre_per_second>>, kilometre_per_hour>);
|
||||
|
||||
static_assert(centimetre::symbol == "cm");
|
||||
|
@@ -20,14 +20,17 @@
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
import os
|
||||
|
||||
from conan import ConanFile
|
||||
from conan.tools.build import cross_building
|
||||
from conan.tools.cmake import CMake
|
||||
from conan.tools.cmake import CMake, cmake_layout
|
||||
|
||||
|
||||
class TestPackageConan(ConanFile):
|
||||
settings = "os", "compiler", "build_type", "arch"
|
||||
generators = "CMakeToolchain", "CMakeDeps"
|
||||
generators = "CMakeDeps", "CMakeToolchain", "VirtualBuildEnv", "VirtualRunEnv"
|
||||
apply_env = False
|
||||
test_type = "explicit" # TODO Remove for Conan 2.0
|
||||
|
||||
def requirements(self):
|
||||
@@ -38,6 +41,10 @@ class TestPackageConan(ConanFile):
|
||||
cmake.configure()
|
||||
cmake.build()
|
||||
|
||||
def layout(self):
|
||||
cmake_layout(self)
|
||||
|
||||
def test(self):
|
||||
if not cross_building(self):
|
||||
self.run("test_package", run_environment=True)
|
||||
cmd = os.path.join(self.cpp.build.bindirs[0], "test_package")
|
||||
self.run(cmd, env="conanrun")
|
||||
|
Reference in New Issue
Block a user