Add 'xo-unit/' from commit 'b531e382c2'
git-subtree-dir: xo-unit git-subtree-mainline:e9ee6992cagit-subtree-split:b531e382c2
This commit is contained in:
commit
d1fa15f248
105 changed files with 11790 additions and 0 deletions
51
xo-unit/.github/workflows/nix-main.yml
vendored
Normal file
51
xo-unit/.github/workflows/nix-main.yml
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
# Workflow to build xo-unit using custom docker container;
|
||||
# container provides nix support
|
||||
#
|
||||
# NOTES
|
||||
# 1. GIT_TOKEN granted automatically by github.
|
||||
# has read permission on public resources + read/write permission on this repo
|
||||
#
|
||||
# 2. container built from [[https:github.com:rconybea/docker-nix-builder]]
|
||||
# Includes dependencies:
|
||||
# - nix
|
||||
# - compiler toolchain: gcc, binutils, bash, etc
|
||||
# - git
|
||||
# - cmake
|
||||
# - catch2
|
||||
# - pybind11 + python
|
||||
# - libwebsockets
|
||||
# - jsoncpp
|
||||
#
|
||||
name: xo-unit nix builder
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
|
||||
env:
|
||||
BUILD_TYPE: Release
|
||||
|
||||
jobs:
|
||||
build_job:
|
||||
name: xo-unit nix build on docker-nix-builder
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
# custom docker image. see github.com:rconybea/docker-nix-builder for definition
|
||||
image: ghcr.io/rconybea/docker-nix-builder:v1
|
||||
|
||||
steps:
|
||||
# not using usual checkout actions: they don't work out-of-the-box from within a container
|
||||
|
||||
- name: xo-unit
|
||||
run: |
|
||||
echo "::group::clone xo-unit repo"
|
||||
mkdir -p repo
|
||||
GIT_SSL_NO_VERIFY=true git clone https://${{env.GIT_USER}}:${{env.GIT_TOKEN}}@github.com/rconybea/xo-unit.git repo/xo-unit
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::build xo-unit with nix"
|
||||
export NIXPKGS_ALLOW_UNFREE=1
|
||||
(cd repo/xo-unit && nix build --impure -L --print-build-logs .#xo-unit && tree ./result)
|
||||
echo "::endgroup"
|
||||
252
xo-unit/.github/workflows/ubuntu-main.yml
vendored
Normal file
252
xo-unit/.github/workflows/ubuntu-main.yml
vendored
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
name: build xo-unit + dependencies
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
|
||||
env:
|
||||
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
|
||||
BUILD_TYPE: Release
|
||||
|
||||
jobs:
|
||||
build:
|
||||
# The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.
|
||||
# You can convert this to a matrix build if you need cross-platform coverage.
|
||||
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: checkout source
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
# install catch2, doxygen. see
|
||||
# [[https://stackoverflow.com/questions/57982945/how-to-apt-get-install-in-a-github-actions-workflow]]
|
||||
|
||||
echo "::group::install catch2"
|
||||
sudo apt-get install -y catch2
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::install doxygen"
|
||||
sudo apt-get install -y doxygen
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::install sphinx"
|
||||
sudo apt-get install -y python3-sphinx
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::install sphinx readthedocs theme"
|
||||
sudo apt-get install -y python3-sphinx-rtd-theme
|
||||
echo "::endgroup"
|
||||
|
||||
#echo "::group::install pybind11"
|
||||
#sudo apt-get install -y pybind11-dev
|
||||
#echo "::endgroup"
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
- name: clone xo-cmake
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: Rconybea/xo-cmake
|
||||
path: repo/xo-cmake
|
||||
|
||||
- name: build xo-cmake
|
||||
run: |
|
||||
XONAME=xo-cmake
|
||||
XOSRC=repo/${XONAME}
|
||||
BUILDDIR=${{github.workspace}}/build_${XONAME}
|
||||
PREFIX=${{github.workspace}}/local
|
||||
|
||||
echo "::group::configure ${XONAME}"
|
||||
cmake -B ${BUILDDIR} -DCMAKE_INSTALL_PREFIX=${PREFIX} ${XOSRC}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::compile ${XONAME}"
|
||||
cmake --build ${BUILDDIR} --config ${{env.BUILD_TYPE}}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::local install ${XONAME}"
|
||||
cmake --install ${BUILDDIR}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::local dir tree"
|
||||
tree ${PREFIX}
|
||||
echo "::endgroup"
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
- name: clone xo-indentlog
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: Rconybea/indentlog
|
||||
path: repo/xo-indentlog
|
||||
|
||||
- name: build xo-indentlog
|
||||
run: |
|
||||
XONAME=xo-indentlog
|
||||
XOSRC=repo/${XONAME}
|
||||
BUILDDIR=${{github.workspace}}/build_${XONAME}
|
||||
PREFIX=${{github.workspace}}/local
|
||||
|
||||
echo "::group::repo dir tree"
|
||||
tree -L 2 repo
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::configure ${XONAME}"
|
||||
cmake -B ${BUILDDIR} -DCMAKE_INSTALL_PREFIX=${PREFIX} ${XOSRC}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::compile ${XONAME}"
|
||||
cmake --build ${BUILDDIR} --config ${{env.BUILD_TYPE}} -j
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::local install ${XONAME}"
|
||||
cmake --install ${BUILDDIR}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::local dir tree"
|
||||
tree -L 3 ${PREFIX}
|
||||
echo "::endgroup"
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
- name: clone xo-flatstring
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: Rconybea/xo-flatstring
|
||||
path: repo/xo-flatstring
|
||||
|
||||
- name: build xo-flatstring
|
||||
run: |
|
||||
XONAME=xo-flatstring
|
||||
XOSRC=repo/${XONAME}
|
||||
BUILDDIR=${{github.workspace}}/build_${XONAME}
|
||||
PREFIX=${{github.workspace}}/local
|
||||
|
||||
echo "::group::repo dir tree"
|
||||
tree -L 2 repo
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::configure ${XONAME}"
|
||||
cmake -B ${BUILDDIR} -DCMAKE_INSTALL_PREFIX=${PREFIX} ${XOSRC}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::compile ${XONAME}"
|
||||
cmake --build ${BUILDDIR} --config ${{env.BUILD_TYPE}} -j
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::local install ${XONAME}"
|
||||
cmake --install ${BUILDDIR}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::local dir tree"
|
||||
tree -L 3 ${PREFIX}
|
||||
echo "::endgroup"
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
- name: clone xo-randomgen
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: Rconybea/randomgen
|
||||
path: repo/xo-randomgen
|
||||
|
||||
- name: build xo-randomgen
|
||||
run: |
|
||||
XONAME=xo-randomgen
|
||||
XOSRC=repo/${XONAME}
|
||||
BUILDDIR=${{github.workspace}}/build_${XONAME}
|
||||
PREFIX=${{github.workspace}}/local
|
||||
|
||||
echo "::group::repo dir tree"
|
||||
tree -L 2 repo
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::configure ${XONAME}"
|
||||
cmake -B ${BUILDDIR} -DCMAKE_INSTALL_PREFIX=${PREFIX} ${XOSRC}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::compile ${XONAME}"
|
||||
cmake --build ${BUILDDIR} --config ${{env.BUILD_TYPE}} -j
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::local install ${XONAME}"
|
||||
cmake --install ${BUILDDIR}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::local dir tree"
|
||||
tree -L 3 ${PREFIX}
|
||||
echo "::endgroup"
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
- name: clone xo-ratio
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: Rconybea/xo-ratio
|
||||
path: repo/xo-ratio
|
||||
|
||||
- name: build xo-ratio
|
||||
run: |
|
||||
XONAME=xo-ratio
|
||||
XOSRC=repo/${XONAME}
|
||||
BUILDDIR=${{github.workspace}}/build_${XONAME}
|
||||
PREFIX=${{github.workspace}}/local
|
||||
|
||||
echo "::group::repo dir tree"
|
||||
tree -L 2 repo
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::configure ${XONAME}"
|
||||
cmake -B ${BUILDDIR} -DCMAKE_INSTALL_PREFIX=${PREFIX} ${XOSRC}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::compile ${XONAME}"
|
||||
cmake --build ${BUILDDIR} --config ${{env.BUILD_TYPE}} -j
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::local install ${XONAME}"
|
||||
cmake --install ${BUILDDIR}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::local dir tree"
|
||||
tree -L 3 ${PREFIX}
|
||||
echo "::endgroup"
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
- name: build self (xo-unit)
|
||||
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
|
||||
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
|
||||
run: |
|
||||
XONAME=xo-unit
|
||||
BUILDDIR=${{github.workspace}}/build_${XONAME}
|
||||
PREFIX=${{github.workspace}}/local
|
||||
|
||||
echo "::group::repo dir tree"
|
||||
tree -L 2 repo
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::configure ${XONAME}"
|
||||
cmake -B ${BUILDDIR} -DCMAKE_MODULE_PATH=${PREFIX}/share/cmake -DCMAKE_PREFIX_PATH=${PREFIX} -DCMAKE_INSTALL_PREFIX=${PREFIX} -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::compile ${XONAME}"
|
||||
cmake --build ${BUILDDIR} --config ${{env.BUILD_TYPE}}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::local install ${XONAME}"
|
||||
cmake --install ${BUILDDIR}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::local dir tree"
|
||||
tree -L 3 ${PREFIX}
|
||||
echo "::endgroup"
|
||||
|
||||
# Execute tests defined by the CMake configuration.
|
||||
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
|
||||
(cd ${BUILDDIR} && ctest -C ${{env.BUILD_TYPE}})
|
||||
248
xo-unit/.github/workflows/xo-cpp-main.yml
vendored
Normal file
248
xo-unit/.github/workflows/xo-cpp-main.yml
vendored
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
name: XO unit builder
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
|
||||
env:
|
||||
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
|
||||
BUILD_TYPE: Release
|
||||
|
||||
jobs:
|
||||
build:
|
||||
# The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.
|
||||
# You can convert this to a matrix build if you need cross-platform coverage.
|
||||
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
container:
|
||||
# custom docker image. see github.com:rconybea/docker-xo-builder for definition
|
||||
image: ghcr.io/rconybea/docker-xo-builder:v1
|
||||
|
||||
steps:
|
||||
- name: xo-cmake
|
||||
run: |
|
||||
# treat github.com as known host to prevent shtoopid SSL errors
|
||||
mkdir -p ~/.ssh
|
||||
ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts
|
||||
cat ~/.ssh/known_hosts
|
||||
|
||||
git config --global http.sslVerify false
|
||||
|
||||
XO_NAME=xo-cmake
|
||||
XO_SRC=repo/${XO_NAME}
|
||||
XO_BUILDDIR=${{github.workspace}}/build_${XO_NAME}
|
||||
PREFIX=${{github.workspace}}/local
|
||||
|
||||
XO_REPO=https://github.com/rconybea/xo-cmake.git
|
||||
|
||||
mkdir -p ${XO_SRC}
|
||||
mkdir -p ${XO_BUILDDIR}
|
||||
|
||||
echo "::group::clone ${XO_NAME}"
|
||||
export GIT_SSH_COMMAND='ssh -o StrictHostKeyChecking=no'
|
||||
export GIT_SSL_NOVERIFY=true
|
||||
git clone ${XO_REPO} ${XO_SRC}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::configure ${XO_NAME}"
|
||||
cmake -B ${XO_BUILDDIR} -DCMAKE_INSTALL_PREFIX=${PREFIX} -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} ${XO_SRC}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::compile ${XO_NAME}"
|
||||
cmake --build ${XO_BUILDDIR} -j
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::local install ${XO_NAME}"
|
||||
cmake --install ${XO_BUILDDIR}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::local dir tree"
|
||||
tree ${PREFIX}
|
||||
echo "::endgroup"
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
- name: xo-indentlog
|
||||
run: |
|
||||
XO_NAME=xo-indentlog
|
||||
XO_SRC=repo/${XO_NAME}
|
||||
XO_BUILDDIR=${{github.workspace}}/build_${XO_NAME}
|
||||
PREFIX=${{github.workspace}}/local
|
||||
|
||||
XO_REPO=https://github.com/rconybea/indentlog.git
|
||||
|
||||
mkdir -p ${XO_SRC}
|
||||
mkdir -p ${XO_BUILDDIR}
|
||||
|
||||
echo "::group::clone ${XO_NAME}"
|
||||
export GIT_SSH_COMMAND='ssh -o StrictHostKeyChecking=no'
|
||||
export GIT_SSL_NOVERIFY=true
|
||||
git clone ${XO_REPO} ${XO_SRC}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::configure ${XO_NAME}"
|
||||
cmake -B ${XO_BUILDDIR} -DCMAKE_INSTALL_PREFIX=${PREFIX} -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} ${XO_SRC}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::compile ${XO_NAME}"
|
||||
cmake --build ${XO_BUILDDIR} -j
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::local install ${XO_NAME}"
|
||||
cmake --install ${XO_BUILDDIR}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::local dir tree"
|
||||
tree ${PREFIX}
|
||||
echo "::endgroup"
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
- name: xo-flatstring
|
||||
run: |
|
||||
XO_NAME=xo-flatstring
|
||||
XO_SRC=repo/${XO_NAME}
|
||||
XO_BUILDDIR=${{github.workspace}}/build_${XO_NAME}
|
||||
PREFIX=${{github.workspace}}/local
|
||||
|
||||
XO_REPO=https://github.com/rconybea/${XO_NAME}.git
|
||||
|
||||
mkdir -p ${XO_SRC}
|
||||
mkdir -p ${XO_BUILDDIR}
|
||||
|
||||
echo "::group::clone ${XO_NAME}"
|
||||
export GIT_SSH_COMMAND='ssh -o StrictHostKeyChecking=no'
|
||||
export GIT_SSL_NOVERIFY=true
|
||||
git clone ${XO_REPO} ${XO_SRC}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::configure ${XO_NAME}"
|
||||
cmake -B ${XO_BUILDDIR} -DCMAKE_INSTALL_PREFIX=${PREFIX} -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} ${XO_SRC}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::compile ${XO_NAME}"
|
||||
cmake --build ${XO_BUILDDIR} -j
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::local install ${XO_NAME}"
|
||||
cmake --install ${XO_BUILDDIR}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::local dir tree"
|
||||
tree ${PREFIX}
|
||||
echo "::endgroup"
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
- name: xo-randomgen
|
||||
run: |
|
||||
XO_NAME=xo-randomgen
|
||||
XO_SRC=repo/${XO_NAME}
|
||||
XO_BUILDDIR=${{github.workspace}}/build_${XO_NAME}
|
||||
PREFIX=${{github.workspace}}/local
|
||||
|
||||
XO_REPO=https://github.com/rconybea/randomgen.git
|
||||
|
||||
mkdir -p ${XO_SRC}
|
||||
mkdir -p ${XO_BUILDDIR}
|
||||
|
||||
echo "::group::clone ${XO_NAME}"
|
||||
export GIT_SSH_COMMAND='ssh -o StrictHostKeyChecking=no'
|
||||
export GIT_SSL_NOVERIFY=true
|
||||
git clone ${XO_REPO} ${XO_SRC}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::configure ${XO_NAME}"
|
||||
cmake -B ${XO_BUILDDIR} -DCMAKE_INSTALL_PREFIX=${PREFIX} -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} ${XO_SRC}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::compile ${XO_NAME}"
|
||||
cmake --build ${XO_BUILDDIR} -j
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::local install ${XO_NAME}"
|
||||
cmake --install ${XO_BUILDDIR}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::local dir tree"
|
||||
tree ${PREFIX}
|
||||
echo "::endgroup"
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
- name: xo-ratio
|
||||
run: |
|
||||
XO_NAME=xo-ratio
|
||||
XO_SRC=repo/${XO_NAME}
|
||||
XO_BUILDDIR=${{github.workspace}}/build_${XO_NAME}
|
||||
PREFIX=${{github.workspace}}/local
|
||||
|
||||
XO_REPO=https://github.com/rconybea/${XO_NAME}.git
|
||||
|
||||
mkdir -p ${XO_SRC}
|
||||
mkdir -p ${XO_BUILDDIR}
|
||||
|
||||
echo "::group::clone ${XO_NAME}"
|
||||
export GIT_SSH_COMMAND='ssh -o StrictHostKeyChecking=no'
|
||||
export GIT_SSL_NOVERIFY=true
|
||||
git clone ${XO_REPO} ${XO_SRC}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::configure ${XO_NAME}"
|
||||
cmake -B ${XO_BUILDDIR} -DCMAKE_INSTALL_PREFIX=${PREFIX} -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} ${XO_SRC}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::compile ${XO_NAME}"
|
||||
cmake --build ${XO_BUILDDIR} -j
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::local install ${XO_NAME}"
|
||||
cmake --install ${XO_BUILDDIR}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::local dir tree"
|
||||
tree ${PREFIX}
|
||||
echo "::endgroup"
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
- name: xo-unit
|
||||
run: |
|
||||
XO_NAME=xo-unit
|
||||
XO_SRC=repo/${XO_NAME}
|
||||
XO_BUILDDIR=${{github.workspace}}/build_${XO_NAME}
|
||||
PREFIX=${{github.workspace}}/local
|
||||
|
||||
XO_REPO=https://github.com/rconybea/${XO_NAME}.git
|
||||
|
||||
mkdir -p ${XO_SRC}
|
||||
mkdir -p ${XO_BUILDDIR}
|
||||
|
||||
echo "::group::clone ${XO_NAME}"
|
||||
export GIT_SSH_COMMAND='ssh -o StrictHostKeyChecking=no'
|
||||
export GIT_SSL_NOVERIFY=true
|
||||
git clone ${XO_REPO} ${XO_SRC}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::configure ${XO_NAME}"
|
||||
cmake -B ${XO_BUILDDIR} -DCMAKE_INSTALL_PREFIX=${PREFIX} -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} ${XO_SRC}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::compile ${XO_NAME}"
|
||||
cmake --build ${XO_BUILDDIR} -j
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::test ${XO_NAME}"
|
||||
cmake --build ${XO_BUILDDIR} -- test
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::local install ${XO_NAME}"
|
||||
cmake --install ${XO_BUILDDIR}
|
||||
echo "::endgroup"
|
||||
|
||||
echo "::group::local dir tree"
|
||||
tree ${PREFIX}
|
||||
echo "::endgroup"
|
||||
8
xo-unit/.gitignore
vendored
Normal file
8
xo-unit/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# emacs projectile config
|
||||
.projectile
|
||||
# clangd working space (see emacs+lsp)
|
||||
.cache
|
||||
# typical cmake build directory (source-tree-nephew)
|
||||
.build*
|
||||
# symlink to builddir/compile_commands.json; should be set manually in dev sandbox
|
||||
compile_commands.json
|
||||
43
xo-unit/CMakeLists.txt
Normal file
43
xo-unit/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
# xo-unit/CMakeLists.txt
|
||||
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
project(xo_unit VERSION 1.0)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
include(cmake/xo-bootstrap-macros.cmake)
|
||||
|
||||
xo_cxx_toplevel_options3()
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
# c++ settings
|
||||
|
||||
# one-time project-specific c++ flags. usually empty
|
||||
set(PROJECT_CXX_FLAGS "-Wstringop-overread")
|
||||
#set(PROJECT_CXX_FLAGS "-fconcepts-diagnostics-depth=2")
|
||||
add_definitions(${PROJECT_CXX_FLAGS})
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
add_subdirectory(example)
|
||||
add_subdirectory(utest)
|
||||
|
||||
set(SELF_LIB xo_unit)
|
||||
xo_add_headeronly_library(${SELF_LIB})
|
||||
xo_install_library4(${SELF_LIB} ${PROJECT_NAME}Targets)
|
||||
xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets)
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
# docs targets depend on all the other library/utest targets
|
||||
#
|
||||
add_subdirectory(docs)
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
# dependencies
|
||||
|
||||
# for some reason, this doesn't reliably bring in xo_flatstring dependency
|
||||
xo_headeronly_dependency(${SELF_LIB} xo_ratio)
|
||||
xo_headeronly_dependency(${SELF_LIB} xo_flatstring)
|
||||
# etc..
|
||||
|
||||
# end CMakeLists.txt
|
||||
29
xo-unit/LICENSE
Normal file
29
xo-unit/LICENSE
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
Copyright (c) 2024 Roland Conybeare <git3ub@nym.hush.com>, All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Please also refer to the file .github/CONTRIBUTING.md, which clarifies licensing of
|
||||
external contributions to this project including patches, pull requests, etc.
|
||||
114
xo-unit/README.md
Normal file
114
xo-unit/README.md
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
# unit library
|
||||
|
||||
Provides compile-time dimension checking and scaling.
|
||||
|
||||
Similar in spirit to `boost::units`, but:
|
||||
1. streamlined: assumes modern (c++20) support
|
||||
2. supports fractional dimensions (rational powers)
|
||||
|
||||
## Documentation
|
||||
|
||||
- xo-unit documentation [under construction]: [documentation](https://rconybea.github.io/web/xo-unit/html/index.html)
|
||||
- unit test coverage here: [coverage](https://rconybea.github.io/web/xo-unit/ccov/html/index.html)
|
||||
|
||||
## Example
|
||||
|
||||
```
|
||||
#include "xo/unit/quantity.hpp"
|
||||
#include "xo/unit/quantity_iostream.hpp"
|
||||
|
||||
namespace q = xo::qty::qty;
|
||||
namespace u = xo::qty::u;
|
||||
|
||||
constexpr auto t = q::minutes(2);
|
||||
constexpr auto d = q::kilometers(2.5);
|
||||
|
||||
constexpr auto t2 = t*t; // unit will be min^-2
|
||||
constexpr auto a = d / t2; // unit will be km.min^-2
|
||||
|
||||
// convert to m.s^-2
|
||||
constexpr quantity<u::meter / (u::second * u::second)> a2 = a;
|
||||
|
||||
//constexpr quantity<u::meter> a3 = a; // dimension mismatch, will not compile
|
||||
|
||||
// get dimensionless scale value
|
||||
double x = a2.scale();
|
||||
```
|
||||
|
||||
## Getting Started
|
||||
|
||||
See [full install instructions](https://rconybea.github.io/web/xo-unit/html/install.html) for other installation strategies.
|
||||
|
||||
### build + install `xo-cmake` dependency
|
||||
|
||||
- [github/Rconybea/xo-cmake](https://github.com/Rconybea/xo-cmake)
|
||||
|
||||
Installs a few cmake ingredients, along with build assistant `xo-build` for XO projects such as this one.
|
||||
|
||||
### build + install other XO dependencies
|
||||
```
|
||||
$ xo-build --clone --configure --build --install xo-flatstring
|
||||
$ xo-build --clone --configure --build --install xo-ratio
|
||||
```
|
||||
|
||||
Note: can use `-n` to dry-run here
|
||||
|
||||
### copy `xo-unit` repository locally
|
||||
```
|
||||
$ xo-build --clone xo-unit
|
||||
```
|
||||
|
||||
or equivalently
|
||||
```
|
||||
$ git clone https://github.com/rconybea/xo-unit
|
||||
```
|
||||
|
||||
### build + install `xo-unit`
|
||||
```
|
||||
$ xo-build --configure --build --install xo-unit
|
||||
```
|
||||
|
||||
or equivalently:
|
||||
```
|
||||
$ PREFIX=/usr/local # or wherever you prefer
|
||||
$ cmake -DCMAKE_INSTALL_PREFIX=${PREFIX} -S xo-unit -B xo-unit/.build
|
||||
$ cmake --build xo-unit/.build -j
|
||||
$ cmake --install xo-unit/.build
|
||||
```
|
||||
|
||||
### build documentation
|
||||
```
|
||||
$ cd xo-unit
|
||||
$ cmake -DCMAKE_INSTALL_PREFIX=${PREFIX} --build .build -- sphinx
|
||||
```
|
||||
When this completes, can point local browser to `xo-unit/.build/docs/sphinx/index.html`.
|
||||
|
||||
### build for unit test coverage
|
||||
|
||||
(Note that unit tests involve additional dependencies):
|
||||
```
|
||||
$ xo-build --clone --configure --build --install xo-indentlog
|
||||
$ xo-build --clone --configure --build --install xo-randomgen
|
||||
```
|
||||
|
||||
```
|
||||
$ cmake -DCMAKE_BUILD_TYPE=coverage -DCMAKE_INSTALL_PREFIX=$PREFIX -DENABLE_TESTING=1 xo-unit/.build-ccov
|
||||
$ cmake --build xo-unit/.build-ccov
|
||||
```
|
||||
|
||||
run coverage-enabled unit tests:
|
||||
```
|
||||
$ cmake --build xo-unit/.build-ccov -- test
|
||||
```
|
||||
|
||||
generate html+text coverage report:
|
||||
```
|
||||
$ xo-unit/.build-ccov/gen-ccov
|
||||
```
|
||||
To see coverage, can point local browser to `xo-unit/.build-ccov/ccov/html/index.html`
|
||||
|
||||
### LSP support
|
||||
```
|
||||
$ cd xo-unit
|
||||
$ ln -s .build/compile_commands.json # lsp will look for compile_commands.json in the root of the source tree
|
||||
```
|
||||
20
xo-unit/cmake/gen-ccov.in
Normal file
20
xo-unit/cmake/gen-ccov.in
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
srcdir=@PROJECT_SOURCE_DIR@
|
||||
builddir=@PROJECT_BINARY_DIR@
|
||||
lcov=@LCOV_EXECUTABLE@
|
||||
genhtml=@GENHTML_EXECUTABLE@
|
||||
|
||||
if [[ $lcov == "LCOV_EXECUTABLE-NOTFOUND" ]]; then
|
||||
echo "gen-ccov: lcov executable not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $genhtml == "GENHTML_EXECUTABLE-NOTFOUND" ]]; then
|
||||
echo "gen-ccov: genhtml executable not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir $builddir/ccov
|
||||
|
||||
$srcdir/cmake/lcov-harness $srcdir $builddir $builddir/ccov/out $lcov $genhtml
|
||||
114
xo-unit/cmake/lcov-harness
Executable file
114
xo-unit/cmake/lcov-harness
Executable file
|
|
@ -0,0 +1,114 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
srcdir=$1
|
||||
builddir=$2
|
||||
outputstem=$3
|
||||
lcov=$4
|
||||
genhtml=$5
|
||||
|
||||
if [[ -z "${srcdir}" ]]; then
|
||||
echo "lcov-harness: expected non-empty srcdir"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z ${builddir} ]]; then
|
||||
echo "lcov-harness: expected non-empty builddir"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z ${outputstem} ]]; then
|
||||
echo "lcov-harness: expected non-empty outputstem"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z ${lcov} ]]; then
|
||||
echo "lcov-harness: exepcted non-empty lcov"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z ${genhtml} ]]; then
|
||||
echo "lcov-harness: expected non-empty genhtml"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# directory stems for location of {.gcda, gcno} coverage information,
|
||||
#
|
||||
# if we have source tree:
|
||||
#
|
||||
# ${srcdir}
|
||||
# +- foo
|
||||
# | \- foo.cpp
|
||||
# \- bar
|
||||
# \- quux
|
||||
# +- quux.cpp
|
||||
# \- quux_main.cpp
|
||||
#
|
||||
# then we expect build tree:
|
||||
#
|
||||
# ${builddir}
|
||||
# +- foo
|
||||
# | \- CMakeFiles
|
||||
# | \- foo_target.dir
|
||||
# | +- foo.cpp.gcda
|
||||
# | \- foo.cpp.gcno
|
||||
# +- bar
|
||||
# \- quux
|
||||
# \- CMakeFiles
|
||||
# \- target4quux.dir
|
||||
# +- quux.cpp.gcda
|
||||
# +- quux.cpp.gcno
|
||||
# +- quux_main.cpp.gcda
|
||||
# \- quux_main.cpp.gcno
|
||||
#
|
||||
# in which case will have cmd_body:
|
||||
#
|
||||
# ${primarydirs}
|
||||
# ./foo/CMakeFiles/foo_target.dir
|
||||
# ./bar/quux/CMakeFiles/target4quux.dir
|
||||
#
|
||||
# here foo_target, quux_target are whatever build is using for corresponding cmake target names.
|
||||
#
|
||||
# We want to invoke lcov like:
|
||||
#
|
||||
# lcov --capture \
|
||||
# --output ${builddir}/ccov \
|
||||
# --exclude /utest/ \
|
||||
# --base-directory ${srcdir}/foo --directory ${builddir}/foo/CMakeFiles/foo_target.dir \
|
||||
# --base-directory ${srcdir}/bar/quux --directory ${builddir}/bar/quux/CMakeFiles/target4quux.dir
|
||||
#
|
||||
primarydirs=$(cd ${builddir} && find -name '*.gcno' \
|
||||
| xargs --replace=xx dirname xx \
|
||||
| uniq \
|
||||
| sed -e 's:^\./::')
|
||||
|
||||
#echo "primarydirs=${primarydirs}"
|
||||
|
||||
cmd="${lcov} --output ${outputstem}.info --capture --ignore-errors source"
|
||||
|
||||
for bdir in ${primarydirs}; do
|
||||
sdir=$(dirname $(dirname ${bdir}))
|
||||
|
||||
cmd="${cmd} --base-directory ${srcdir}/${sdir} --directory ${builddir}/${bdir}"
|
||||
done
|
||||
|
||||
#echo cmd=${cmd}
|
||||
|
||||
set -x
|
||||
|
||||
# capture
|
||||
${cmd}
|
||||
|
||||
# keep only files with paths under source tree
|
||||
# (don't want coverage for external libraries such as libstdc++ etc)
|
||||
${lcov} --extract ${outputstem}.info "${srcdir}/*" --output ${outputstem}2.info
|
||||
|
||||
# remove unit test dirs
|
||||
# (we're interested in coverage of our installed code, not of the unit tests that exercise it)
|
||||
${lcov} --remove ${outputstem}2.info '*/utest/*' --output ${outputstem}3.info
|
||||
|
||||
# generate .html tree
|
||||
mkdir -p ${builddir}/ccov/html
|
||||
${genhtml} --ignore-errors source --show-details --prefix ${srcdir} --output-directory ${builddir}/ccov/html ${outputstem}3.info
|
||||
|
||||
# also send report to stdout
|
||||
${lcov} --list ${outputstem}3.info
|
||||
35
xo-unit/cmake/xo-bootstrap-macros.cmake
Normal file
35
xo-unit/cmake/xo-bootstrap-macros.cmake
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# ----------------------------------------------------------------
|
||||
# for example:
|
||||
# $ PREFIX=/usr/local # for example
|
||||
# $ cmake -DCMAKE_MODULE_PATH=prefix -DCMAKE_INSTALL_PREFIX=$PREFIX -B .build
|
||||
#
|
||||
# will get
|
||||
# CMAKE_MODULE_PATH
|
||||
# from xo-cmake-config --cmake-module-path
|
||||
#
|
||||
# and expect .cmake macros in
|
||||
# CMAKE_MODULE_PATH/xo_macros/xo_cxx.cmake
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
find_program(XO_CMAKE_CONFIG_EXECUTABLE NAMES xo-cmake-config REQUIRED)
|
||||
|
||||
if ("${XO_CMAKE_CONFIG_EXECUTABLE}" STREQUAL "XO_CMAKE_CONFIG_EXECUTABLE-NOT_FOUND")
|
||||
message(FATAL "could not find xo-cmake-config executable")
|
||||
endif()
|
||||
|
||||
message(STATUS "XO_CMAKE_CONFIG_EXECUTABLE=${XO_CMAKE_CONFIG_EXECUTABLE}")
|
||||
|
||||
if (NOT XO_SUBMODULE_BUILD)
|
||||
if (("${CMAKE_MODULE_PATH}" STREQUAL "") OR ("${CMAKE_MODULE_PATH}" STREQUAL prefix))
|
||||
# default to typical install location for xo-project-macros
|
||||
execute_process(COMMAND ${XO_CMAKE_CONFIG_EXECUTABLE} --cmake-module-path OUTPUT_VARIABLE CMAKE_MODULE_PATH)
|
||||
message(STATUS "CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# needs to have been installed somewhere on CMAKE_MODULE_PATH,
|
||||
# (e.g. from xo-cmake with the same value for CMAKE_INSTALL_PREFIX)
|
||||
#
|
||||
include(xo_macros/xo_cxx)
|
||||
|
||||
xo_cxx_bootstrap_message()
|
||||
11
xo-unit/cmake/xo_unitConfig.cmake.in
Normal file
11
xo-unit/cmake/xo_unitConfig.cmake.in
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
@PACKAGE_INIT@
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
|
||||
find_dependency(xo_ratio)
|
||||
find_dependency(indentlog)
|
||||
#find_dependency(printjson)
|
||||
#find_dependency(callback)
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
|
||||
check_required_components("@PROJECT_NAME@")
|
||||
17
xo-unit/docs/CMakeLists.txt
Normal file
17
xo-unit/docs/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
# xo-unit/docs/CMakeLists.txt
|
||||
|
||||
xo_doxygen_collect_deps()
|
||||
xo_docdir_doxygen_config()
|
||||
xo_docdir_sphinx_config(
|
||||
index.rst examples.rst glossary.rst install.rst implementation.rst
|
||||
quantity-reference.rst quantity-class.rst quantity-factoryfunctions.rst quantity-unitvars.rst quantity-source-code.rst
|
||||
xquantity-reference.rst xquantity-class.rst xquantity-source-code.rst
|
||||
scaled-unit-reference.rst scaled-unit-class.rst scaled-unit-constants.rst
|
||||
natural-unit-class.rst
|
||||
bpu-class.rst
|
||||
bu-store-class.rst basis-unit-reference.rst
|
||||
basis-unit-class.rst basis-unit-constants.rst
|
||||
dimension-enum.rst
|
||||
development.rst
|
||||
ubuntu-github-workflow.rst
|
||||
)
|
||||
70
xo-unit/docs/README
Normal file
70
xo-unit/docs/README
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
build
|
||||
|
||||
+-----------------------------------------------+
|
||||
| cmake |
|
||||
| CMakeLists.txt |
|
||||
| $PREFIX/share/cmake/xo_macros/xo_cxx.cmake |
|
||||
+-----------------------------------------------+
|
||||
|
|
||||
| +----------------------+
|
||||
+------------------------------------------------->| .build/docs/Doxyfile |
|
||||
| +----------------------+
|
||||
| |
|
||||
| /------------/
|
||||
| |
|
||||
| v
|
||||
| +---------------------------------------+ +-----------------+
|
||||
+---->| doxygen |--->| .build/docs/dox |
|
||||
| | $PREFIX/share/xo-macros/Doxyfile.in | | +- html/ |
|
||||
| +---------------------------------------+ | +- xml/ |
|
||||
| +-----------------+
|
||||
| |
|
||||
| /------------/
|
||||
| |
|
||||
| v
|
||||
| +---------------------------------------+ +--------------------+
|
||||
\---->| sphinx |--->| .build/docs/sphinx |
|
||||
| +- conf.py | | +- html/ |
|
||||
| +- _static/ | +--------------------+
|
||||
| +- *.rst |
|
||||
+---------------------------------------+
|
||||
|
||||
files
|
||||
|
||||
README this file
|
||||
CMakeLists.txt build entry point
|
||||
conf.py sphinx config
|
||||
_static static files for sphinx
|
||||
|
||||
map
|
||||
|
||||
index.rst
|
||||
+- install.rst
|
||||
+- examples.rst
|
||||
+- unit-quantities.rst
|
||||
+- classes.rst
|
||||
+- glossary.rst
|
||||
...
|
||||
|
||||
examples
|
||||
|
||||
.. doxygenclass:: ${c++ class name}
|
||||
:project:
|
||||
:path:
|
||||
:members:
|
||||
:protected-members:
|
||||
:private-members:
|
||||
:undoc-members:
|
||||
:member-groups:
|
||||
:members-only:
|
||||
:outline:
|
||||
:no-link:
|
||||
:allow-dot-graphs:
|
||||
|
||||
.. doxygendefine:: ${c preprocessor define}
|
||||
|
||||
.. doxygenconcept:: ${c++ concept definition}
|
||||
|
||||
.. doxygenenum:: ${c++ enum definition}
|
||||
|
||||
.. doxygenfunction:: ${c++ function name}
|
||||
1
xo-unit/docs/_static/README
vendored
Normal file
1
xo-unit/docs/_static/README
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
add any static {.html, .js, ..} files for sphinx to pickup here
|
||||
BIN
xo-unit/docs/_static/img/favicon.ico
vendored
Normal file
BIN
xo-unit/docs/_static/img/favicon.ico
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 302 KiB |
76
xo-unit/docs/basis-unit-class.rst
Normal file
76
xo-unit/docs/basis-unit-class.rst
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
.. _basis-unit-class:
|
||||
|
||||
Basis Unit
|
||||
==========
|
||||
|
||||
A unit representing a fixed multiple of a native dimension.
|
||||
|
||||
Context
|
||||
-------
|
||||
|
||||
.. ditaa::
|
||||
:--scale: 0.85
|
||||
|
||||
+----------------+---------------+
|
||||
| quantity | xquantity |
|
||||
+----------------+---------------+
|
||||
| scaled_unit |
|
||||
+--------------------------------+
|
||||
| natural_unit |
|
||||
+--------------------------------+
|
||||
| bpu |
|
||||
+----------------+ |
|
||||
| bu_store | |
|
||||
+----------------+---------------+
|
||||
|cBLU basis_unit |
|
||||
+--------------------------------+
|
||||
| dimension |
|
||||
+--------------------------------+
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
A :code:`basis_unit` represents a unit belonging to a single native dimension.
|
||||
For example :code:`bu::meter` representing a distance of 1 meter.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <xo/unit/basis_unit.hpp>
|
||||
|
||||
.. uml::
|
||||
:scale: 99%
|
||||
:align: center
|
||||
:caption: basis unit representing 1 minute
|
||||
|
||||
object bu1<<basis_unit>>
|
||||
bu1 : native_dim = time
|
||||
bu1 : scalefactor = 60
|
||||
|
||||
:code:`basis_unit` is intended as an implementation-level abstraction.
|
||||
Application code will normally interact with the more-capable :code:`scaled_unit`
|
||||
instead of :code:`basis_unit`.
|
||||
|
||||
Class
|
||||
-----
|
||||
|
||||
.. doxygenclass:: xo::qty::basis_unit
|
||||
|
||||
Member Variables
|
||||
----------------
|
||||
|
||||
.. doxygengroup:: basis-unit-instance-vars
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. doxygengroup:: basis-unit-constructors
|
||||
|
||||
Access Methods
|
||||
--------------
|
||||
|
||||
.. doxygengroup:: basis-unit-access-methods
|
||||
|
||||
Comparison
|
||||
----------
|
||||
|
||||
.. doxygengroup:: basis-unit-comparison-support
|
||||
60
xo-unit/docs/basis-unit-constants.rst
Normal file
60
xo-unit/docs/basis-unit-constants.rst
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
.. _basis-unit-constants:
|
||||
|
||||
Basis Unit Constants
|
||||
====================
|
||||
|
||||
Relative scalefactors for each built-in unit.
|
||||
|
||||
Context
|
||||
-------
|
||||
|
||||
.. ditaa::
|
||||
:--scale: 0.85
|
||||
|
||||
+----------------+---------------+
|
||||
| quantity | xquantity |
|
||||
+----------------+---------------+
|
||||
| scaled_unit |
|
||||
+--------------------------------+
|
||||
| natural_unit |
|
||||
+--------------------------------+
|
||||
| bpu |
|
||||
+----------------+ |
|
||||
| bu_store | |
|
||||
+----------------+---------------+
|
||||
|cBLU basis_unit |
|
||||
+--------------------------------+
|
||||
| dimension |
|
||||
+--------------------------------+
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Constants in the :code:`xo::qty::detail::bu` namespace represent
|
||||
low-level building blocks for specifying units.
|
||||
Relative scalefactors for each unit are chosen here.
|
||||
|
||||
Application code will not typically use these values directtly;
|
||||
instead it's expected to use units from the :code:`xo::qty::u` namespace.
|
||||
Those units are implemented on top of the basis units described here.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <xo/unit/basis_unit.hpp>
|
||||
|
||||
using xo::qty::detail::bu;
|
||||
|
||||
Mass Units
|
||||
----------
|
||||
|
||||
.. doxygengroup:: basis-unit-mass-units
|
||||
|
||||
Distance Units
|
||||
--------------
|
||||
|
||||
.. doxygengroup:: basis-unit-distance-units
|
||||
|
||||
Time Units
|
||||
----------
|
||||
|
||||
.. doxygengroup:: basis-unit-time-units
|
||||
31
xo-unit/docs/basis-unit-reference.rst
Normal file
31
xo-unit/docs/basis-unit-reference.rst
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
.. _basis-unit-reference:
|
||||
|
||||
Basis Unit Reference
|
||||
====================
|
||||
|
||||
Built-in named units for each native dimension
|
||||
|
||||
.. ditaa::
|
||||
:--scale: 0.85
|
||||
|
||||
+----------------+---------------+
|
||||
| quantity | xquantity |
|
||||
+----------------+---------------+
|
||||
| scaled_unit |
|
||||
+--------------------------------+
|
||||
| natural_unit |
|
||||
+--------------------------------+
|
||||
| bpu |
|
||||
+----------------+ |
|
||||
| bu_store | |
|
||||
+----------------+---------------+
|
||||
|cBLU basis_unit |
|
||||
+--------------------------------+
|
||||
| dimension |
|
||||
+--------------------------------+
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
Basis Unit Class <basis-unit-class>
|
||||
basis-unit-constants
|
||||
98
xo-unit/docs/bpu-class.rst
Normal file
98
xo-unit/docs/bpu-class.rst
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
.. _bpu-class:
|
||||
|
||||
BPU
|
||||
===
|
||||
|
||||
A rational (usually integral) power of a single basis unit
|
||||
|
||||
Context
|
||||
-------
|
||||
|
||||
.. ditaa::
|
||||
:--scale: 0.85
|
||||
|
||||
+----------------+---------------+
|
||||
| quantity | xquantity |
|
||||
+----------------+---------------+
|
||||
| scaled_unit |
|
||||
+--------------------------------+
|
||||
| natural_unit |
|
||||
+--------------------------------+
|
||||
|cBLU bpu |
|
||||
+----------------+ |
|
||||
| bu_store | |
|
||||
+----------------+---------------+
|
||||
| basis_unit |
|
||||
+--------------------------------+
|
||||
| dimension |
|
||||
+--------------------------------+
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <xo/unit/bpu.hpp>
|
||||
|
||||
A :code:`xo::qty::bpu` (aka "basis power unit") represents a rational (usually integer) power of a :doc:`basis-unit-class`.
|
||||
|
||||
For example:
|
||||
|
||||
.. uml::
|
||||
:caption: representation for cubic millimeters
|
||||
:scale: 99%
|
||||
:align: center
|
||||
|
||||
object mm3<<bpu>>
|
||||
mm3 : native_dim = dim::distance
|
||||
mm3 : scalefactor = 1/1000
|
||||
mm3 : power = 3/1
|
||||
|
||||
.. uml::
|
||||
:caption: representation for annual (365-day) volatility
|
||||
:scale: 99%
|
||||
:align: center
|
||||
|
||||
object vol<<bpu>>
|
||||
vol : native_dim = dim::time
|
||||
vol : scalefactor = 365*24*3600
|
||||
vol : power = -1/2
|
||||
|
||||
:code:`bpu` is intended as an implementation-level abstraction.
|
||||
Application code will normally interact with the more-general :code:`scaled_unit`
|
||||
instead of :code:`bpu`.
|
||||
|
||||
Class
|
||||
-----
|
||||
|
||||
.. doxygenclass:: xo::qty::bpu
|
||||
|
||||
Member Variables
|
||||
----------------
|
||||
|
||||
.. doxygengroup:: bpu-instance-vars
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. doxygengroup:: bpu-ctors
|
||||
|
||||
Access Methods
|
||||
--------------
|
||||
|
||||
.. doxygengroup:: bpu-access-methods
|
||||
|
||||
Other Methods
|
||||
-------------
|
||||
|
||||
.. doxygengroup:: bpu-methods
|
||||
|
||||
Comparison
|
||||
----------
|
||||
|
||||
.. doxygengroup:: bpu-comparison
|
||||
|
||||
Details
|
||||
-------
|
||||
|
||||
.. doxygengroup:: bpu-abbrev-helpers
|
||||
129
xo-unit/docs/bu-store-class.rst
Normal file
129
xo-unit/docs/bu-store-class.rst
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
.. _bu-store-class:
|
||||
|
||||
Basis Unit Store
|
||||
================
|
||||
|
||||
.. ditaa::
|
||||
:--scale: 0.85
|
||||
|
||||
+----------------+---------------+
|
||||
| quantity | xquantity |
|
||||
+----------------+---------------+
|
||||
| scaled_unit |
|
||||
+--------------------------------+
|
||||
| natural_unit |
|
||||
+--------------------------------+
|
||||
| bpu |
|
||||
+----------------+ |
|
||||
|cBLU bu_store | |
|
||||
+----------------+---------------+
|
||||
| basis_unit |
|
||||
+--------------------------------+
|
||||
| dimension |
|
||||
+--------------------------------+
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <xo/unit/bu_store.hpp>
|
||||
|
||||
namespace bu = xo::qty::detail::bu;
|
||||
|
||||
A :code:`xo::qty::bu_store` is a small, constexpr, key-value store associating
|
||||
abbreviations with basis units. To satisfy the constexpr requirement,
|
||||
all unit abbreviations are irrevocably established from ``bu_store``'s constructor.
|
||||
|
||||
The constant ``bu_abbrev_store`` contains a single instance of ``bu_store``,
|
||||
recording all built-in units along with their associated abbreviations
|
||||
|
||||
.. uml::
|
||||
:caption: basis-unit store
|
||||
:scale: 99%
|
||||
:align: center
|
||||
|
||||
map mass_table<<bu_dim_store>> {
|
||||
bu::milligram => "mg"
|
||||
bu::gram => "g"
|
||||
bu::kilogram => "kg"
|
||||
}
|
||||
|
||||
map distance_table<<bu_dim_store>> {
|
||||
bu::millimeter => "mm"
|
||||
bu::meter => "m"
|
||||
bu::kilometer => "km"
|
||||
}
|
||||
|
||||
map time_table<<bu_dim_store>> {
|
||||
bu::millisecond => "ms"
|
||||
bu::second => "s"
|
||||
bu::minute => "min"
|
||||
bu::hour => "hr"
|
||||
}
|
||||
|
||||
object bu_abbrev_store<<bu_store>>
|
||||
bu_abbrev_store : bu_abbrev_vv[dim::mass] = mass_table
|
||||
bu_abbrev_store : bu_abbrev_vv[dim::distance] = distance_table
|
||||
bu_abbrev_store : bu_abbrev_vv[dim::time] = time_table
|
||||
|
||||
bu_abbrev_store o-- mass_table
|
||||
bu_abbrev_store o-- distance_table
|
||||
bu_abbrev_store o-- time_table
|
||||
|
||||
|
||||
This class exists to support the implementation of ``natural_unit::abbrev()``.
|
||||
|
||||
Application code is not expected to interact directly with it.
|
||||
|
||||
Class
|
||||
-----
|
||||
|
||||
.. doxygenclass:: xo::qty::detail::bu_store
|
||||
|
||||
For example, this would be possible:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <xo/unit/bu_store.hpp>
|
||||
|
||||
namespace bu = using xo::qty::detail::bu;
|
||||
using xo::qty::detail::bu_store;
|
||||
using xo::qty::dim;
|
||||
using xo::flatstring;
|
||||
|
||||
constexpr bu_store store;
|
||||
static_assert(store.bu_abbrev(bu::minute) == flatstring("min"));
|
||||
static_assert(store.bu_abbrev(bu::microgram) == flatstring("ug"));
|
||||
|
||||
.. doxygengroup:: bu-store-constructors
|
||||
.. doxygengroup:: bu-store-access-methods
|
||||
.. doxygengroup:: bu-store-implementation-methods
|
||||
|
||||
.. doxygenclass:: xo::qty::detail::bu_dim_store
|
||||
.. doxygengroup:: bu-dim-store-type-traits
|
||||
.. doxygengroup:: bu-dim-store-instance-vars
|
||||
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
Provides dictionary of unit abbreviations
|
||||
|
||||
Application code is not expected to interact directly with ``bu_abbrev_store``.
|
||||
|
||||
.. doxygenvariable:: xo::qty::bu_abbrev_store
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. doxygenfunction:: xo::qty::bu_abbrev
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <xo/unit/bu_store.hpp>
|
||||
|
||||
namespace bu = xo::qty::bu;
|
||||
using xo::qty::bu_abbrev;
|
||||
using xo::flatstring;
|
||||
|
||||
static_assert(bu_abbrev(bu::kilogram) == xo::flatstring("kg"));
|
||||
39
xo-unit/docs/conf.py
Normal file
39
xo-unit/docs/conf.py
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# For the full list of built-in configuration values, see the documentation:
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
||||
|
||||
project = 'xo unit documentation'
|
||||
copyright = '2024, Roland Conybeare'
|
||||
author = 'Roland Conybeare'
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
||||
|
||||
#extensions = []
|
||||
extensions = [ "breathe",
|
||||
"sphinx.ext.mathjax", # inline math
|
||||
"sphinx.ext.autodoc", # generate info from docstrings
|
||||
"sphinxcontrib.ditaa", # diagrams-through-ascii-art
|
||||
"sphinxcontrib.plantuml" # text -> uml diagrams
|
||||
]
|
||||
|
||||
# note: breathe requires doxygen xml output -> must have GENERATE_XML = YES in Doxyfile.in
|
||||
# match project name in Doxyfile.in
|
||||
breathe_default_project = "xodoxxml"
|
||||
|
||||
templates_path = ['_templates']
|
||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
|
||||
|
||||
#html_theme = 'alabaster'
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
html_static_path = ['_static']
|
||||
html_favicon = '_static/img/favicon.ico'
|
||||
18
xo-unit/docs/development.rst
Normal file
18
xo-unit/docs/development.rst
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
.. _development:
|
||||
|
||||
Development
|
||||
===========
|
||||
|
||||
Miscellaneous development notes for *xo-unit*.
|
||||
|
||||
Addding a Basis Unit
|
||||
--------------------
|
||||
|
||||
To add a basis unit for an existing dimension:
|
||||
|
||||
#. add unit definition to the ``xo::qty::bu`` namespace in ``include/xo/unit/basis_unit.hpp``
|
||||
#. add call to ``bu_store::bu_establish_abbrev()`` from ``bu_store::bu_store``.
|
||||
#. add ``natural_unit`` definition to ``xo::qty::nu`` namespace in ``include/xo/unit/natural_unit.hpp``
|
||||
#. add ``scaled_unit`` definition to ``xo::qty::u`` namespace in ``include/xo/unit/scaled_unit.hpp``.
|
||||
#. add unit quantity to ``xo::qty::qty`` namespace in ``include/xo/unit/quantity.hpp``
|
||||
#. add factory function to ``xo::qty::qty`` namespace in ``include/xo/unit/quantity.hpp``
|
||||
66
xo-unit/docs/dimension-enum.rst
Normal file
66
xo-unit/docs/dimension-enum.rst
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
.. _dimension:
|
||||
|
||||
Native Dimension
|
||||
================
|
||||
|
||||
An abstract dimension; distinct native dimensions are orthogonal
|
||||
|
||||
Context
|
||||
-------
|
||||
|
||||
.. ditaa::
|
||||
:--scale: 0.85
|
||||
|
||||
+----------------+---------------+
|
||||
| quantity | xquantity |
|
||||
+----------------+---------------+
|
||||
| scaled_unit |
|
||||
+--------------------------------+
|
||||
| natural_unit |
|
||||
+--------------------------------+
|
||||
| bpu |
|
||||
+----------------+ |
|
||||
| bu_store | |
|
||||
+----------------+---------------+
|
||||
| basis_unit |
|
||||
+--------------------------------+
|
||||
|cBLU dimension |
|
||||
+--------------------------------+
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Identifies an abstract dimension, for example *mass* or *time*.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <xo/unit/dimension.hpp>
|
||||
|
||||
For example can use this enum to index basis members of a :doc:`scaled_unit<scaled-unit-class>` instance:
|
||||
|
||||
.. code-block:: cpp
|
||||
:emphasize-lines: 7-8
|
||||
|
||||
#include <xo/unit/quantity.hpp>
|
||||
|
||||
using namespace xo::qty;
|
||||
|
||||
auto x = q::kilometers(100) / q::hours(1);
|
||||
|
||||
auto bpu1 = x.lookup_dim(dim::time);
|
||||
auto bpu2 = x.lookup_dim(dim::distance);
|
||||
|
||||
Enum
|
||||
----
|
||||
|
||||
.. doxygenenum:: xo::qty::dimension
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. doxygenvariable:: xo::qty::n_dim
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. doxygenfunction:: xo::qty::dim2str
|
||||
366
xo-unit/docs/examples.rst
Normal file
366
xo-unit/docs/examples.rst
Normal file
|
|
@ -0,0 +1,366 @@
|
|||
.. _examples:
|
||||
|
||||
.. toctree
|
||||
:maxdepth: 2
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
Compile-time unit inference
|
||||
---------------------------
|
||||
|
||||
See ``xo-unit/examples/ex1`` for code below.
|
||||
|
||||
Units propagate through familiar arithmetic expressions:
|
||||
|
||||
.. code-block:: cpp
|
||||
:linenos:
|
||||
:emphasize-lines: 14-15
|
||||
|
||||
#include "xo/unit/quantity.hpp"
|
||||
#include "xo/unit/quantity_iostream.hpp"
|
||||
#include <iostream>
|
||||
|
||||
int
|
||||
main () {
|
||||
namespace q = xo::qty::qty;
|
||||
namespace su = xo::qty::su;
|
||||
using namespace std;
|
||||
|
||||
constexpr auto t = q::minutes(2);
|
||||
constexpr auto d = q::kilometers(2.5);
|
||||
|
||||
constexpr auto t2 = t*t;
|
||||
constexpr auto a = d / (t*t);
|
||||
|
||||
cerr << "t: " << t << ", d: " << d
|
||||
<< ", t^2: " << t2
|
||||
<< ", d.t^-2: " << a
|
||||
<< endl;
|
||||
}
|
||||
|
||||
with output:
|
||||
|
||||
.. code-block::
|
||||
|
||||
t: 2min, d: 2.5km, t^2: 4min^2, d.t^-2: 0.625km.min^-2
|
||||
|
||||
We can use static asserts to prove that units are being computed at compile-time
|
||||
|
||||
.. code-block:: cpp
|
||||
:linenos:
|
||||
|
||||
static_assert(std::same_as<decltype(t)::repr_type, int>);
|
||||
static_assert(sizeof(t) == sizeof(double));
|
||||
static_assert(t.scale() == 2);
|
||||
static_assert(t.abbrev() == flatstring("min"));
|
||||
|
||||
static_assert(std::same_as<decltype(d)::repr_type, double>);
|
||||
static_assert(sizeof(d) == sizeof(double));
|
||||
static_assert(d.scale() == 2.5);
|
||||
static_assert(d.abbrev() == flatstring("km"));
|
||||
|
||||
static_assert(std::same_as<decltype(t2)::repr_type, int>);
|
||||
static_assert(sizeof(t2) == sizeof(double));
|
||||
static_assert(t2.scale() == 4);
|
||||
static_assert(t2.abbrev() == flatstring("min^2"));
|
||||
|
||||
static_assert(std::same_as<decltype(a)::repr_type, double>);
|
||||
static_assert(sizeof(a) == sizeof(double));
|
||||
static_assert(a.scale() == 0.625);
|
||||
static_assert(a.abbrev() == flatstring("km.min^-2"));
|
||||
|
||||
Remarks:
|
||||
|
||||
- ``xo::qty::quantity`` performs unit consistency checking and propagation at compile time. Runtime space/time overhead is zero.
|
||||
- Units are sticky: since we expressed ``t`` in minutes, ``(t*t)`` and ``d/(t*t)`` also use minutes.
|
||||
- Unit ordering is sticky. Distance appears on the left of time in printed value of ``d/(t*t)``
|
||||
because it was on the left-hand side of ``operator/``
|
||||
- ``xo-unit`` copies representation from the argument to factory functions ``q::minutes``, ``q::kilometers`` etc.
|
||||
- Binary operators take representation from the 'most precise' argument, as prescribed by ``std::common_type_t``.
|
||||
- Unit abbreviations (such as ``kg.min^-2`` above) are computed at compile time.
|
||||
See ``xo::flatstring`` for constexpr string implementation.
|
||||
- See ``xo::xquantity`` for parallel implementation that defers unit checking until runtime.
|
||||
|
||||
|
||||
Explicit scale conversion
|
||||
-------------------------
|
||||
|
||||
Can convert between compatible units explictly,
|
||||
using:
|
||||
|
||||
1. ``xo::qty::with_units`` (template function)
|
||||
2. ``quantity.rescale_ext`` (template method)
|
||||
3. ``xo::qty::with_units_from`` (template function)
|
||||
|
||||
See ``xo-unit/examples/ex2`` for code below.
|
||||
|
||||
.. code-block:: cpp
|
||||
:linenos:
|
||||
:emphasize-lines: 10,13,16-17
|
||||
|
||||
#include "xo/unit/quantity.hpp"
|
||||
#include "xo/unit/quantity_iostream.hpp"
|
||||
#include <iostream>
|
||||
|
||||
int
|
||||
main () {
|
||||
namespace q = xo::qty::qty;
|
||||
namespace u = xo::qty::u;
|
||||
using xo::qty::with_units_from;
|
||||
using xo::qty::with_units;
|
||||
using xo::qty::quantity;
|
||||
using xo::flatstring;
|
||||
using namespace std;
|
||||
|
||||
constexpr auto t = q::minutes(2);
|
||||
constexpr auto d = q::kilometers(2.5);
|
||||
|
||||
constexpr auto t2 = t*t;
|
||||
constexpr auto a = d / (t*t);
|
||||
|
||||
cerr << "t: " << t << ", d: " << d
|
||||
<< ", t^2: " << t2
|
||||
<< ", d.t^-2: " << a
|
||||
<< endl;
|
||||
|
||||
constexpr auto a2 = with_units<u::meter / (u::second * u::second)>(a);
|
||||
|
||||
static_assert(a2.abbrev() == flatstring("m.s^-2"));
|
||||
|
||||
cerr << "a2: " << a2 << endl;
|
||||
|
||||
constexpr auto a3 = a.rescale_ext<u::meter / (u::second * u::second)>();
|
||||
|
||||
static_assert(a3.abbrev() == flatstring("m.s^-2"));
|
||||
|
||||
cerr << "a3: " << a3 << endl;
|
||||
|
||||
constexpr auto au = q::meter / (q::second * q::second);
|
||||
constexpr auto a4 = with_units_from(a, au);
|
||||
|
||||
static_assert(a4.abbrev() == flatstring("m.s^-2"));
|
||||
|
||||
cerr << "a4: " << a4 << endl;
|
||||
}
|
||||
|
||||
with output:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
a2: 0.173611m.s^-2
|
||||
a3: 0.173611m.s^-2
|
||||
a4: 0.173611m.s^-2
|
||||
|
||||
Implicit Scale conversion
|
||||
-------------------------
|
||||
|
||||
Another way to convert units is to assign to a variable
|
||||
with desired units -- this works because the units are encoded
|
||||
as part of the assigned variable's type.
|
||||
|
||||
See ``xo-unit/example/ex3`` for code below
|
||||
|
||||
.. code-block:: cpp
|
||||
:linenos:
|
||||
:emphasize-lines: 12-13
|
||||
|
||||
int
|
||||
main () {
|
||||
namespace q = xo::qty::qty;
|
||||
namespace u = xo::qty::u;
|
||||
using xo::qty::quantity;
|
||||
|
||||
constexpr quantity<u::second> t = q::minutes(2);
|
||||
constexpr quantity<u::meter> d = q::kilometers(2.5);
|
||||
|
||||
constexpr auto t2 = t*t;
|
||||
constexpr auto a = d / (t*t);
|
||||
|
||||
std::cerr << "t: " << t << ", d: " << d
|
||||
<< ", d.t^-2: " << a
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
with output:
|
||||
|
||||
.. code-block::
|
||||
|
||||
t: 120s, d: 2500m, d.t^-2: 0.17e611m.s^-2
|
||||
|
||||
Remarks:
|
||||
|
||||
- Assignment to ``t`` converted to representation ``double``.
|
||||
We could have instead used :code:`quantity<u::second, int>` to propagate
|
||||
right-hand-side representation
|
||||
|
||||
Scale conversion and arithmetic
|
||||
-------------------------------
|
||||
|
||||
When representing a particular quantity,
|
||||
xo-unit uses at most one scale for each :term:`basis dimension` associated with the unit for that quantity.
|
||||
When an arithmetic operator encounters basis units involving two different scales,
|
||||
the operator will adopt the scale provided by the left-hand argument:
|
||||
|
||||
See ``xo-unit/example/ex4`` for code below
|
||||
|
||||
.. code-block:: cpp
|
||||
:linenos:
|
||||
:emphasize-lines: 11
|
||||
|
||||
#include "xo/unit/quantity.hpp"
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
namespace q = xo::qty::qty;
|
||||
|
||||
auto t1 = qty::milliseconds(1);
|
||||
auto t2 = qty::minutes(1);
|
||||
auto p = t1 * t2;
|
||||
|
||||
std::cerr << "t1: " << t1 << ", t2: " << t2 << ", p: " << p << std::endl;
|
||||
}
|
||||
|
||||
with output:
|
||||
|
||||
.. code-block::
|
||||
|
||||
t1: 1ms, t2: 1min, t1*t2: 60000ms^2
|
||||
|
||||
|
||||
Dimensionless quantities unwrap implicitly
|
||||
------------------------------------------
|
||||
|
||||
Conversely, compiler rejects attempt to implictly unwrap a dimensioned quantity.
|
||||
|
||||
See ``xo-unit/examples/ex4`` for code below.
|
||||
|
||||
.. code-block:: cpp
|
||||
:linenos:
|
||||
:emphasize-lines: 23,26
|
||||
|
||||
#include "xo/unit/quantity.hpp"
|
||||
#include "xo/unit/quantity_iostream.hpp"
|
||||
#include <iostream>
|
||||
|
||||
int
|
||||
main () {
|
||||
namespace q = xo::qty::qty;
|
||||
|
||||
auto t1 = q::milliseconds(1);
|
||||
auto t2 = q::minutes(1);
|
||||
|
||||
auto r1 = t1 / with_repr<double>(t2);
|
||||
|
||||
static_assert(r1.is_dimensionless());
|
||||
static_assert(!t2.is_dimensionless());
|
||||
|
||||
static_assert(std::same_as<static_cast<double>(r1), double>);
|
||||
|
||||
// r1_value: assignment compiles, since r1 dimensionless
|
||||
double r1_value = r1;
|
||||
|
||||
// r2_value: bad assignment won't compile, 'cannot convert' error
|
||||
//double r2_value = t2;
|
||||
|
||||
std::cerr << "t1: " << t1 << ", t2: " << t2 << ", t1/t2: " << r1_value << std::endl;
|
||||
}
|
||||
|
||||
with output:
|
||||
|
||||
.. code-block::
|
||||
|
||||
t1: 1ms, t2: 1min, t1/t2: 1.66667e-05
|
||||
|
||||
|
||||
Fractional dimension
|
||||
--------------------
|
||||
|
||||
Fractional dimensions have limited support.
|
||||
Prior to c++26 we can only support fractional dimensions with denominator 2,
|
||||
such as powers -3/2, -1/2, +1/2, +3/2 etc.
|
||||
|
||||
c++26 will enable support for support fractional dimensions involving other ratios,
|
||||
by offering constexpr ``::pow()``
|
||||
|
||||
See ``xo-unit/examples/ex6`` for code below
|
||||
|
||||
.. code-block:: cpp
|
||||
:linenos:
|
||||
:emphasize-lines: 15
|
||||
|
||||
#include "xo/unit/quantity.hpp"
|
||||
#include "xo/unit/quantity_iostream.hpp"
|
||||
#include <iostream>
|
||||
|
||||
int
|
||||
main () {
|
||||
namespace u = xo::unit::units;
|
||||
namespace q = xo::unit::qty;
|
||||
using namespace std;
|
||||
|
||||
/* 20% volatility over 250 days (approx number of trading days in one year) */
|
||||
auto q1 = q::volatility_250d(0.2);
|
||||
/* 10% volatility over 30 days */
|
||||
auto q2 = q::volatility_30d(0.1);
|
||||
|
||||
auto sum = q1 + q2;
|
||||
auto prod = q1 * q2;
|
||||
|
||||
static_assert(sum.abbrev() == flatstring("yr360^(-1/2)"));
|
||||
static_assert(prod.abbrev() == flatstring("yr360^-1"));
|
||||
|
||||
std::cerr << "q1: " << q1 << std::endl;
|
||||
std::cerr << "q2: " << q2 << std::endl;
|
||||
std::cerr << "q1+q2: " << sum << std::endl;
|
||||
std::cerr << "q1*q2: " << prod << std::endl;
|
||||
}
|
||||
|
||||
with output:
|
||||
|
||||
.. code-block::
|
||||
|
||||
q1: 0.2yr360^(-1/2)
|
||||
q2: 0.1mo^(-1/2)
|
||||
q1+q2: 0.54641yr360^(-1/2)
|
||||
q1*q2: 0.069282yr360^-1
|
||||
|
||||
|
||||
Dynamic dimension
|
||||
-----------------
|
||||
|
||||
If the dimension (or units) associated with a quantity are not known at compile-time,
|
||||
use ``xo::qty::xquantity`` instead of ``xo::qty::quantity``.
|
||||
|
||||
See ``xo-unit/example/ex8`` for code below
|
||||
|
||||
.. code-block:: cpp
|
||||
:linenos:
|
||||
:emphasize-lines: 10-12
|
||||
|
||||
#include "xo/unit/xquantity.hpp"
|
||||
#include "xo/unit/xquantity_iostream.hpp"
|
||||
#include <iostream>
|
||||
|
||||
int
|
||||
main () {
|
||||
using namespace xo::qty;
|
||||
namespace u = xo::qty::u;
|
||||
|
||||
xquantity qty1(7, u::foot);
|
||||
xquantity qty2(6.0, u::inch);
|
||||
xquantity qty3 = qty1 + qty2;
|
||||
|
||||
std::cerr << "qty1: " << qty1 << std::endl;
|
||||
std::cerr << "qty2: " << qty2 << std::endl;
|
||||
std::cerr << "qty3: " << qty3 << std::endl;
|
||||
|
||||
/* rescale to mm */
|
||||
xquantity res = qty3.rescale(xo::qty::nu::millimeter);
|
||||
|
||||
/* 2286mm */
|
||||
std::cerr << "res: " << res << std::endl;
|
||||
}
|
||||
|
||||
Here ``u::foot`` and ``u::inch`` are literals,
|
||||
but they could have been read from console input or another runtime-only context.
|
||||
43
xo-unit/docs/glossary.rst
Normal file
43
xo-unit/docs/glossary.rst
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
.. _glossary:
|
||||
|
||||
Glossary
|
||||
--------
|
||||
|
||||
.. glossary::
|
||||
dimension
|
||||
dim
|
||||
| Fundamental, orthogonal directions associated available for constructing units.
|
||||
| For example *mass*, *length*, *time*.
|
||||
| In *xo-unit* these are represented by the enum :doc:`xo::qty::dimension<dimension-enum>`.
|
||||
|
||||
basis unit
|
||||
bu
|
||||
| An implementation type representing a quantity (with associated scale) in the direction of a single :term:`dimension`.
|
||||
| For example *milliseconds*, *seconds*, and *hours* stand for different basis units within the *time* dimension.
|
||||
| In *xo-unit* these are represented by the template type :doc:`xo::qty::basis_unit<basis-unit-class>`.
|
||||
|
||||
basis power unit
|
||||
bpu
|
||||
| A rational power of a (single) basis unit.
|
||||
| For example :math:`s^{-2}` for unit "per second squared" or :math:`yr^{-(1/2)}` for "per square-root of a year".
|
||||
| In *xo-unit* these are represented by the template type :doc:`xo::qty::bpu<bpu-class>`
|
||||
|
||||
natural unit
|
||||
nu
|
||||
| A cartesian product of basis power units (bpus);
|
||||
| For example :math:`kg.m.s^{-2}` or :math:`hr^{-(1/2)}`.
|
||||
| In *xo-unit* these are represented by template type :doc:`xo::qty::natural_unit<natural-unit-class>`.
|
||||
|
||||
scaled unit
|
||||
su
|
||||
| A dimensionless multiple of a natural unit.
|
||||
| Used as intermediate value when coalescing quantities involving different units.
|
||||
| In *xo-unit* these are represented by template type :doc:`xo::qty::scaled_unit<scaled-unit-class>`.
|
||||
|
||||
XO
|
||||
A set of integrated c++ libraries for complex event processing, with browser and python integration.
|
||||
`xo documentation here`_
|
||||
|
||||
.. _xo documentation here: https://rconybea.github.io/web/sw/xo.html
|
||||
|
||||
.. toctree::
|
||||
314
xo-unit/docs/implementation.rst
Normal file
314
xo-unit/docs/implementation.rst
Normal file
|
|
@ -0,0 +1,314 @@
|
|||
.. _implementation:
|
||||
|
||||
Components
|
||||
==========
|
||||
|
||||
Library dependency tower for *xo-unit*:
|
||||
|
||||
.. ditaa::
|
||||
|
||||
+-----------------+
|
||||
| xo_unit |
|
||||
+-----------------+
|
||||
| xo_ratio |
|
||||
+-----------------+
|
||||
| xo_flatstring |
|
||||
+-----------------+
|
||||
| xo_cmake |
|
||||
+-----------------+
|
||||
|
||||
Install instructions :doc:`here<install>`
|
||||
|
||||
Abstraction tower for *xo-unit* components:
|
||||
|
||||
.. ditaa::
|
||||
:--scale: 0.85
|
||||
|
||||
+----------------+---------------+
|
||||
| quantity | xquantity |
|
||||
+----------------+---------------+
|
||||
| scaled_unit |
|
||||
+--------------------------------+
|
||||
| natural_unit |
|
||||
+--------------------------------+
|
||||
| bpu |
|
||||
+----------------+ |
|
||||
| bu_store | |
|
||||
+----------------+---------------+
|
||||
| basis_unit |
|
||||
+--------------------------------+
|
||||
| dimension |
|
||||
+--------------------------------+
|
||||
|
||||
- :doc:`quantity<quantity-reference>`:
|
||||
|
||||
A quantity with unit checking and conversion done at compile-time
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include "xo/unit/quantity.hpp"
|
||||
auto q1 = xo::qty::qty::kilometers(7.5);
|
||||
|
||||
- :doc:`xquantity<xquantity-reference>`:
|
||||
|
||||
A quantity with unit checking and conversion done at run-time.
|
||||
This is useful if unit information isn't known at compile time, for example
|
||||
if reading units from console input.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include "xo/unit/xquantity.hpp"
|
||||
xquantity qty1(7.5, xo::qty::u::foot)
|
||||
|
||||
|
||||
- :doc:`scaled_unit<scaled-unit-class>`:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include "xo/unit/scaled_unit.hpp"
|
||||
auto u = xo::qty::u::millimeter;
|
||||
|
||||
A unit involving zero or more dimensions, and associated conversion factor.
|
||||
|
||||
- can express result of arithmetic involving multiple scales,
|
||||
by reporting an outer scalefactor
|
||||
- a scaled unit is 'natural' if its outer scalefactor is 1.
|
||||
- quantities are represented by associating a natural scaled_unit instance
|
||||
- scaled_units are closed under multiplication and division.
|
||||
- multiplication and division commit to a single :code:`basis_unit` for each
|
||||
dimension.
|
||||
|
||||
- :doc:`natural_unit<natural-unit-class>`
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include "xo/unit/natural_unit.hpp"
|
||||
auto u = xo::qty::nu::millimeter;
|
||||
|
||||
A unit involving zero or more dimensions, and at most one scale per dimension.
|
||||
A quantity instance is always represented as a dimensionless multiple
|
||||
of a natural unit
|
||||
|
||||
- natural_units are *not* closed under multiplication and division.
|
||||
(for example consider :code:`xo::qty::qty::foot * xo::qty::qty::meter`)
|
||||
|
||||
- :doc:`bpu<bpu-class>`
|
||||
|
||||
A rational (usually integer) power of a basis unit. Has a single dimension.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include "xo/unit/bpu.hpp"
|
||||
xo::qty::bpu(xo::qty::detail::bu::millimeter,
|
||||
xo::qty::power_ratio_type(2)); // mm^2
|
||||
|
||||
- :doc:`bu_store<bu-store-class>`
|
||||
|
||||
Associates basis units with abbreviations.
|
||||
Abbreviations used to decorate printed quantities.
|
||||
|
||||
For example ``bu::kilogram`` => ``"kg"``
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include "xo/unit/bu_store.hpp"
|
||||
xo::qty::bu_abbrev_store.bu_abbrev(xo::qty::detail::bu::picogram); // "pg"
|
||||
|
||||
- :doc:`basis_unit<basis-unit-reference>`
|
||||
|
||||
A unit with a single dimension and scale.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include "xo/unit/basis_unit.hpp"
|
||||
auto b = xo::qty::detail::bu::picogram;
|
||||
|
||||
- :doc:`dimension<dimension-enum>`
|
||||
|
||||
identifies a dimension, such as mass or time.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include "xo/unit/dimension.hpp"
|
||||
auto d = xo::qty::dimension::mass;
|
||||
|
||||
Representation
|
||||
==============
|
||||
|
||||
Worked example using :cpp:class:`xo::qty::quantity`.
|
||||
|
||||
.. code-block:: cpp
|
||||
:linenos:
|
||||
:emphasize-lines: 6
|
||||
|
||||
#include "xo/unit/quantity.hpp"
|
||||
...
|
||||
using xo::qty;
|
||||
namespace q = xo::qty::qty;
|
||||
|
||||
// 7.55km.min^-2
|
||||
quantity qty1 = 7.55 * q::kilometer / (q::minute * q::minute);
|
||||
|
||||
Note: in diagrams below, components with pale blue background are discarded before runtime
|
||||
|
||||
.. uml::
|
||||
:caption: representation for quantity 7.55km.min^-2
|
||||
:scale: 99%
|
||||
:align: center
|
||||
|
||||
object qty1<<quantity>>
|
||||
qty1 : scale = 7.55
|
||||
|
||||
rectangle #e0f0ff {
|
||||
|
||||
object km_per_min2<<natural_unit>>
|
||||
km_per_min2 : n_bpu = 2
|
||||
km_per_min2 : bpu[0] = km
|
||||
km_per_min2 : bpu[1] = per_min
|
||||
|
||||
object km<<bpu>>
|
||||
km : native_dim = dim.mass
|
||||
km : scalefactor = 1000/1
|
||||
km : power = 1
|
||||
|
||||
object per_min2<<bpu>>
|
||||
per_min2 : native_dim = dim.time
|
||||
per_min2 : scalefactor = 60/1
|
||||
per_min2 : power = -2
|
||||
|
||||
qty1 o-- km_per_min2 : s_unit (static constexpr)
|
||||
|
||||
km_per_min2 *-- km
|
||||
km_per_min2 *-- per_min2
|
||||
|
||||
}
|
||||
|
||||
.. code-block:: cpp
|
||||
:linenos:
|
||||
|
||||
// 123ng
|
||||
quantity qty2 = q::nanograms(123);
|
||||
|
||||
.. uml::
|
||||
:caption: representation for quantity 123 nanograms
|
||||
:scale: 99%
|
||||
:align: center
|
||||
|
||||
object qty2<<quantity>>
|
||||
qty2 : scale = 123
|
||||
|
||||
rectangle #e0f0ff {
|
||||
|
||||
object ng_unit<<natural_unit>>
|
||||
ng_unit : n_bpu = 1
|
||||
ng_unit : bpu[0] = ng
|
||||
|
||||
object ng<<bpu>>
|
||||
ng : native_dim = dim::mass
|
||||
ng : scalefactor = 1/10^9
|
||||
ng : power = 1
|
||||
|
||||
qty2 o-- ng_unit : s_unit (static constexpr)
|
||||
|
||||
ng_unit *-- ng
|
||||
|
||||
}
|
||||
|
||||
.. code-block:: cpp
|
||||
:linenos:
|
||||
|
||||
// (123*7.55) ng.km.min^-2
|
||||
quantity qty3 = qty2 * qty1;
|
||||
|
||||
.. uml::
|
||||
:caption: quantity 928.65 ng.km.min^-2
|
||||
:scale: 99%
|
||||
:align: center
|
||||
|
||||
object qty3<<quantity>>
|
||||
qty3 : scale = 928.65
|
||||
|
||||
rectangle #e0f0ff {
|
||||
|
||||
object ng_km_min2_unit<<natural_unit>>
|
||||
ng_km_min2_unit : n_bpu = 3
|
||||
ng_km_min2_unit : bpu[0] = ng
|
||||
ng_km_min2_unit : bpu[1] = km
|
||||
ng_km_min2_unit : bpu[2] = per_min2
|
||||
|
||||
object ng<<bpu>>
|
||||
ng : native_dim = dim::mass
|
||||
ng : scalefactor = 1/10^9
|
||||
ng : power = 1
|
||||
|
||||
object km<<bpu>>
|
||||
km : native_dim = dim::distance
|
||||
km : scalefactor = 1000/1
|
||||
km : power = 1
|
||||
|
||||
object per_min2<<bpu>>
|
||||
per_min2 : native_dim = dim::time
|
||||
per_min2 : scalefactor = 60/1
|
||||
per_min2 : power = -2
|
||||
|
||||
qty3 o-- ng_km_min2_unit : s_unit (static constexpr)
|
||||
|
||||
ng_km_min2_unit *-- ng
|
||||
ng_km_min2_unit *-- km
|
||||
ng_km_min2_unit *-- per_min2
|
||||
}
|
||||
|
||||
.. code-block:: cpp
|
||||
:linenos:
|
||||
|
||||
namespace u = xo::qty::u;
|
||||
|
||||
// (123*7.55) ng.km.min^-2 ==> 2.57958e-10kg.m.s^-2
|
||||
|
||||
constexpr auto newton = u::kilogram * u::meter / (u::second * u::second);
|
||||
|
||||
quantity<newton> qty3b = qty3;
|
||||
|
||||
// quantity qty3b = qty3.rescale_ext<newton>();
|
||||
|
||||
.. uml::
|
||||
:caption: quantity 928.65 ng.km.min^-2
|
||||
:scale: 99%
|
||||
:align: center
|
||||
|
||||
object qty3b<<quantity>>
|
||||
qty3b : scale = 2.59758e-10
|
||||
|
||||
rectangle #e0f0ff {
|
||||
|
||||
object kg_m_s2_unit<<natural_unit>>
|
||||
kg_m_s2_unit : n_bpu = 3
|
||||
kg_m_s2_unit : bpu[0] = kg
|
||||
kg_m_s2_unit : bpu[1] = m
|
||||
kg_m_s2_unit : bpu[2] = per_s2
|
||||
|
||||
object kg<<bpu>>
|
||||
kg : native_dim = dim::mass
|
||||
kg : scalefactor = 1000/1
|
||||
kg : power = 1
|
||||
|
||||
object m<<bpu>>
|
||||
m : native_dim = dim::distance
|
||||
m : scalefactor = 1/1
|
||||
m : power = 1
|
||||
|
||||
object per_s2<<bpu>>
|
||||
per_s2 : native_dim = dim::time
|
||||
per_s2 : scalefactor = 1/1
|
||||
per_s2 : power = -2
|
||||
|
||||
qty3b o-- kg_m_s2_unit : s_unit (static constexpr)
|
||||
|
||||
kg_m_s2_unit *-- kg
|
||||
kg_m_s2_unit *-- m
|
||||
kg_m_s2_unit *-- per_s2
|
||||
}
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Abstractions
|
||||
48
xo-unit/docs/index.rst
Normal file
48
xo-unit/docs/index.rst
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
.. xo-unit-examples documentation master file, created by
|
||||
sphinx-quickstart on Wed Mar 6 23:32:27 2024.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
xo-unit documentation
|
||||
=====================
|
||||
|
||||
xo-unit is a lightweight header-only library that provides compile-time
|
||||
dimension checking and unit conversion.
|
||||
|
||||
Functionality is similar in spirit to that provided by ``boost::units``;
|
||||
however there are some important differences:
|
||||
|
||||
* streamlined implementation using c++20 features.
|
||||
* along with no-runtime-overhead compile-time unit inference,
|
||||
also provides defer-until-runtime representation.
|
||||
* constexpr string representation for things like unit abbreviations.
|
||||
* supports fractional dimensions, for concepts like volatility.
|
||||
* integration with python (see sister project xo-pyunit)
|
||||
|
||||
Second, ``xo-unit`` supports fractional dimensions. This allows using it to naturally handle
|
||||
concepts like volatility (dimension 1/sqrt(time)), for example.
|
||||
|
||||
Finally, ``xo-unit`` is written with the expectation of providing
|
||||
python integration via pybind11. This requires a parallel set of data structures that can work at
|
||||
runtime (since we can't construct new c++ types at runtime).
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: xo-unit contents
|
||||
|
||||
install
|
||||
examples
|
||||
implementation
|
||||
quantity-reference
|
||||
xquantity-reference
|
||||
scaled-unit-reference
|
||||
natural-unit-class
|
||||
bpu-class
|
||||
bu-store-class
|
||||
basis-unit-reference
|
||||
dimension-enum
|
||||
development
|
||||
ubuntu-github-workflow
|
||||
glossary
|
||||
genindex
|
||||
search
|
||||
305
xo-unit/docs/install.rst
Normal file
305
xo-unit/docs/install.rst
Normal file
|
|
@ -0,0 +1,305 @@
|
|||
.. _install:
|
||||
|
||||
.. toctree
|
||||
:maxdepth: 2
|
||||
|
||||
Install
|
||||
=======
|
||||
|
||||
``xo-unit`` uses supporting header-only libraries ``xo-ratio`` and ``xo-flatstring``.
|
||||
and (optionally) cmake macros ``xo-cmake``. These are on github:
|
||||
|
||||
- `xo-unit source`_ (constexpr quantities, units and dimension-checking)
|
||||
- `xo-ratio source`_ (constexpr exact ratios)
|
||||
- `xo-flatstring source`_ (constexpr strings)
|
||||
- `xo-cmake source`_ (shared cmake macros)
|
||||
|
||||
.. _xo-unit source: https://github.com/rconybea/xo-unit
|
||||
.. _xo-ratio source: https://github.com/rconybea/xo-ratio
|
||||
.. _xo-flatstring source: https://github.com/rconybea/xo-flatstring
|
||||
.. _xo-cmake source: https://github.com/rconybea/xo-cmake
|
||||
|
||||
`xo-cmake` is nccessary to invoke `xo` cmake build for:
|
||||
|
||||
- site install
|
||||
- example programs
|
||||
- unit tests
|
||||
|
||||
Can omit to instead copy `xo_unit`, `xo-ratio` and `xo-flatstring` source trees;
|
||||
see instructions below for including as git submodule
|
||||
|
||||
Implementation relies on some c++20 features (for example class-instances as template arguments).
|
||||
Tested with gcc 12.3, 13.2
|
||||
|
||||
Include as submodule
|
||||
--------------------
|
||||
|
||||
One way to use ``xo-unit`` in a project is to import the source tree directly:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd myproject
|
||||
git submodule add -b main https://github.com/rconybea/xo-flatstring ext/xo-flatstring
|
||||
git submodule add -b main https://github.com/rconybea/xo-ratio ext/xo-ratio
|
||||
git submodule add -b main https://github.com/rconybea/xo-unit ext/xo-unit
|
||||
git submodule update --init
|
||||
|
||||
This assumes you organize directly-incorporated dependencies under directory ``myproject/ext``.
|
||||
You would then add to your compiler's include path the directories ``myproject/ext/xo-flatstring/include``,
|
||||
``myproject/ext/xo-ratio/include``, ``myproject/ext/xo-unit/include``;
|
||||
|
||||
and add
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
#include <xo/unit/quantity.hpp>
|
||||
|
||||
to c++ source files that rely on xo-unit
|
||||
|
||||
Ubuntu Install Pattern
|
||||
----------------------
|
||||
|
||||
:doc:`Example instructions<ubuntu-github-workflow>` (used for github actions CI) for build starting from stock ubuntu
|
||||
|
||||
Installing from source
|
||||
----------------------
|
||||
|
||||
Install scripts for `xo-unit`, `xo-ratio` and `xo-flatstring` depend on shared cmake macros
|
||||
and a bootstrap script `xo-cmake-config` from `xo-cmake`.
|
||||
|
||||
Preamble:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
mkdir -p ~/proj/xo
|
||||
cd ~/proj/xo
|
||||
|
||||
git clone https://github.com/rconybea/xo-cmake
|
||||
git clone https://github.com/rconybea/xo-flatstring
|
||||
git clone https://github.com/rconybea/xo-ratio
|
||||
git clone https://github.com/rconybea/xo-unit
|
||||
|
||||
PREFIX=~/local # ..or other desired installation prefix
|
||||
|
||||
Ordering below is important; cmake support for each subsystem
|
||||
requires successful installation of its predecessor.
|
||||
|
||||
Install `xo-cmake`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -B xo-cmake/.build -S xo-cmake
|
||||
cmake --build xo-cmake/.build -j # placeholder, no-op for now
|
||||
cmake --install xo-cmake/.build
|
||||
|
||||
Build and Install `xo-flatstring`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -DENABLE_TESTING=0 \
|
||||
-B xo-flatstring/.build -S xo-flatstring
|
||||
cmake --build xo-flatstring/.build -j
|
||||
cmake --install xo-flatstring/.build
|
||||
|
||||
Build and Install `xo-ratio`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -DENABLE_TESTING=0 \
|
||||
-B xo-ratio/.build -S xo-ratio
|
||||
cmake --build xo-ratio/.build -j
|
||||
cmake --install xo-ratio/.build
|
||||
|
||||
Build and Install `xo-unit`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -DENABLE_TESTING=0 \
|
||||
-B xo-unit/.build -S xo-unit
|
||||
cmake --build xo-unit/.build -j
|
||||
cmake --install xo-unit/.build
|
||||
|
||||
Directories under ``PREFIX`` will then contain:
|
||||
|
||||
.. code-block::
|
||||
|
||||
PREFIX
|
||||
+- bin
|
||||
| \- xo-cmake-config
|
||||
+- include
|
||||
| \- xo
|
||||
| +- cxxutil/
|
||||
| +- flatstring/
|
||||
| +- ratio/
|
||||
| +- unit/
|
||||
+- lib
|
||||
| \- cmake
|
||||
| +- indentlog/
|
||||
| +- randomgen/
|
||||
| +- xo_flatstring/
|
||||
| \- xo_unit/
|
||||
+- share
|
||||
\- cmake
|
||||
\- xo_macros/
|
||||
|
||||
Use CMake Support
|
||||
-----------------
|
||||
|
||||
To use built-in cmake suport:
|
||||
|
||||
Make sure ``PREFIX/lib/cmake`` is searched by cmake (if necessary, include it in ``CMAKE_PREFIX_PATH``)
|
||||
|
||||
Add to ``CMakeLists.txt``:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
FindPackage(xo_unit CONFIG REQUIRED)
|
||||
|
||||
target_link_libraries(mytarget INTERFACE xo_unit)
|
||||
|
||||
Build and Install with Unit Tests Enabled
|
||||
-----------------------------------------
|
||||
|
||||
Running unit tests require a few additional dependencies:
|
||||
|
||||
* `catch2`_ header-only unit-test framework
|
||||
* `xo-indentlog`_ logging with call-structure indenting
|
||||
* `xo-randomgen`_ fast random number generator (xoshiro256ss)
|
||||
|
||||
.. _catch2: https://github.com/catchorg/Catch2
|
||||
.. _xo-indentlog: https://github.com/rconybea/indentlog
|
||||
.. _xo-randomgen: https://github.com/rconybea/randomgen
|
||||
|
||||
Preamble:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
mkdir -p ~/proj/xo
|
||||
cd ~/proj/xo
|
||||
|
||||
git clone https://github.com/rconybea/xo-cmake
|
||||
git clone https://github.com/rconybea/indentlog xo-indentlog
|
||||
git clone https://github.com/rconybea/randomgen xo-randomgen
|
||||
git clone https://github.com/rconybea/xo-flatstring
|
||||
git clone https://github.com/rconybea/xo-ratio
|
||||
git clone https://github.com/rconybea/xo-unit
|
||||
|
||||
PREFIX=~/local # ..or other desired installation prefix
|
||||
|
||||
Build and Install `catch2` (assuming ubuntu here):
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo apt-get install catch2 # on ubuntu, for example
|
||||
|
||||
Build and Install `xo-cmake`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -B xo-cmake/.build -S xo-cmake
|
||||
cmake --build xo-cmake/.build -j # placeholder, no-op for now
|
||||
cmake --install xo-cmake/.build
|
||||
|
||||
Build, Test and Install `xo-indentlog`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -B xo-indentlog/.build -S xo-indentlog
|
||||
cmake --build xo-indentlog/.build -j
|
||||
cmake --build xo-indentlog/.build -- test # run unit tests, cmake invokes ctest
|
||||
(cd xo-indentlog/.build && ctest) # or invoke ctest directly
|
||||
cmake --install xo-indentlog/.build
|
||||
|
||||
Build and Install `xo-randomgen` (no unit tests yet):
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -B xo-randomgen/.build -S xo-randomgen
|
||||
cmake --build xo-randomgen/.build -j
|
||||
cmake --install xo-randomgen/.build
|
||||
|
||||
Build, Test and Install `xo-flatstring`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -B xo-flatstring/.build -S xo-flatstring
|
||||
cmake --build xo-flatstring/.build -j
|
||||
cmake --build xo-flatstring/.build -- test # run unit tests, cmake invokes ctest
|
||||
(cd xo-flatstring/.build && ctest) # or invoke ctest directly
|
||||
cmake --install xo-flatstring/.build
|
||||
|
||||
Build, Test and Install `xo-ratio`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -B xo-ratio/.build -S xo-ratio
|
||||
cmake --build xo-ratio/.build -j
|
||||
cmake --build xo-ratio/.build -- test # run unit tests, cmake invokes ctest
|
||||
(cd xo-ratio/.build && ctest) # or invoke ctest directly
|
||||
cmake --install xo-ratio/.build
|
||||
|
||||
Build, Test and Install `xo-unit`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -B xo-unit/.build -S xo-unit
|
||||
cmake --build xo-unit/.build -j
|
||||
cmake --build xo-unit/.build -- test # run unit tests, cmake invokes ctest
|
||||
(cd xo-unit/.build && ctest) # or invoke ctest directly
|
||||
cmake --install xo-unit/.build
|
||||
|
||||
Build Examples
|
||||
--------------
|
||||
|
||||
To enable building example programs:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd ~/proj/xo
|
||||
cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -DXO_ENABLE_EXAMPLES=1 -B xo-unit/.build -S xo-unit
|
||||
|
||||
Run examples from the build directory:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
~/proj/xo/xo-unit/.build/example/ex1/xo_unit_ex1
|
||||
~/proj/xo/xo-unit/.build/example/ex2/xo_unit_ex2
|
||||
# etc
|
||||
|
||||
Build and Install Documentation
|
||||
-------------------------------
|
||||
|
||||
xo-unit documentation has these additional dependencies:
|
||||
|
||||
* `doxygen`_ annotation-driven inline documentation
|
||||
* `sphinx`_ documentation based on ReST files
|
||||
* `sphinx-rtd-theme`_ popular CSS theme for sphinx
|
||||
* `breathe`_ make doxygen-generated ingredients available from sphinx
|
||||
|
||||
.. _doxygen: https://www.doxygen.nl
|
||||
.. _sphinx: https://www.sphinx-doc.org
|
||||
.. _sphinx-rtd-theme: https://pypi.org/project/sphinx-rtd-theme
|
||||
.. _breathe: https://breathe.readthedocs.io/en/latest
|
||||
|
||||
Preamble (assuming ubuntu here):
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo apt-get install doxygen
|
||||
sudo apt-get install python3-sphinx
|
||||
sudo apt-get install python3-sphinx-rtd-theme
|
||||
sudo apt-get install python3-breathe
|
||||
|
||||
Build `xo-unit` docs
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd ~/proj/xo
|
||||
cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -B xo-unit/.build
|
||||
cmake --build xo-unit/.build -- docs
|
||||
cmake --install xo-unit/.build # if docs built, installs to $PREFIX/share/doc/xo_unit/html
|
||||
|
||||
Supported compilers
|
||||
-------------------
|
||||
|
||||
* developed with gcc 12.3.0 and gcc 13.2.0; github CI using gcc 11.4.0 (asof March 2024)
|
||||
109
xo-unit/docs/natural-unit-class.rst
Normal file
109
xo-unit/docs/natural-unit-class.rst
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
.. _natural-unit-class:
|
||||
|
||||
Natural Unit
|
||||
============
|
||||
|
||||
A natural unit represents a product of terms, each involving a distinct basis dimension
|
||||
|
||||
Context
|
||||
-------
|
||||
|
||||
.. ditaa::
|
||||
:--scale: 0.85
|
||||
|
||||
+----------------+---------------+
|
||||
| quantity | xquantity |
|
||||
+----------------+---------------+
|
||||
| scaled_unit |
|
||||
+--------------------------------+
|
||||
|cBLU natural_unit |
|
||||
+--------------------------------+
|
||||
| bpu |
|
||||
+----------------+ |
|
||||
| bu_store | |
|
||||
+----------------+---------------+
|
||||
| basis_unit |
|
||||
+--------------------------------+
|
||||
| dimension |
|
||||
+--------------------------------+
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <xo/unit/natural_unit.hpp>
|
||||
|
||||
Representation for the unit associated with a :doc:`xquantity<xquantity-class>`
|
||||
|
||||
- represents a cartesian product of basis units.
|
||||
- constexpr implementation
|
||||
- limited support for fractional dimensions such as time^-1/2
|
||||
|
||||
.. uml::
|
||||
:caption: natural unit for a Newton (unit of force)
|
||||
:scale: 99%
|
||||
:align: center
|
||||
|
||||
object newton<<natural_unit>>
|
||||
newton : n_bpu = 3
|
||||
newton : bpu_v[]
|
||||
|
||||
object kg<<bpu>>
|
||||
kg : native_dim = dim::mass
|
||||
kg : scalefactor = 1000/1
|
||||
kg : power = 1/1
|
||||
|
||||
object m<<bpu>>
|
||||
m : native_dim = dim::distance
|
||||
m : scalefactor = 1/1
|
||||
m : power = 1/1
|
||||
|
||||
object s2<<bpu>>
|
||||
s2 : native_dim = dim::time
|
||||
s2 : scalefactor = 1/1
|
||||
s2 : power = -2/1
|
||||
|
||||
newton o-- kg
|
||||
newton o-- m
|
||||
newton o-- s2
|
||||
|
||||
Class
|
||||
-----
|
||||
|
||||
.. doxygenclass:: xo::qty::natural_unit
|
||||
|
||||
Member Variables
|
||||
----------------
|
||||
|
||||
.. doxygengroup:: natural-unit-instance-vars
|
||||
|
||||
Type Traits
|
||||
-----------
|
||||
|
||||
.. doxygengroup:: natural-unit-type-traits
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. doxygengroup:: natural-unit-ctors
|
||||
|
||||
Access Methods
|
||||
--------------
|
||||
|
||||
.. doxygengroup:: natural-unit-access-methods
|
||||
|
||||
General Methods
|
||||
---------------
|
||||
|
||||
.. doxygengroup:: natural-unit-methods
|
||||
|
||||
Conversion
|
||||
----------
|
||||
|
||||
.. doxygengroup:: natural-unit-conversion-methods
|
||||
|
||||
Comparison Functions
|
||||
--------------------
|
||||
|
||||
.. doxygengroup:: natural-unit-comparison-functions
|
||||
144
xo-unit/docs/quantity-class.rst
Normal file
144
xo-unit/docs/quantity-class.rst
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
.. _quantity-class:
|
||||
|
||||
Quantity
|
||||
========
|
||||
|
||||
Dimensioned quantity with compile-time unit checking/conversion
|
||||
|
||||
Context
|
||||
-------
|
||||
|
||||
.. ditaa::
|
||||
:--scale: 0.85
|
||||
|
||||
+----------------+---------------+
|
||||
|cBLU quantity | xquantity |
|
||||
+----------------+---------------+
|
||||
| scaled_unit |
|
||||
+--------------------------------+
|
||||
| natural_unit |
|
||||
+--------------------------------+
|
||||
| bpu |
|
||||
+----------------+ |
|
||||
| bu_store | |
|
||||
+----------------+---------------+
|
||||
| basis_unit |
|
||||
+--------------------------------+
|
||||
| dimension |
|
||||
+--------------------------------+
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <xo/unit/quantity.hpp>
|
||||
|
||||
.. uml::
|
||||
:scale: 99%
|
||||
:align: center
|
||||
|
||||
allowmixing
|
||||
|
||||
object qty1<<quantity>>
|
||||
qty1 : scale = 1.23
|
||||
|
||||
rectangle constexpr #e0f0ff {
|
||||
|
||||
object unit<<scaled_unit>>
|
||||
unit : is_natural() = true
|
||||
|
||||
qty1 o-- unit : s_scaled_unit (static constexpr)
|
||||
|
||||
}
|
||||
|
||||
- Arithmetic on :doc:`xo::qty::quantity<quantity-reference>` instances
|
||||
does *not* use ``xo::qty::quantity::s_scaled_unit`` at runtime;
|
||||
instead gets everything it needs at compile time.
|
||||
|
||||
- The :code:`xo::qty::quantity` template takes a :doc:`xo::qty::scaled_unit<scaled-unit-class>` instance,
|
||||
but only accepts values with :code:`xo::qty::scaled_unit::is_natural() == true`.
|
||||
|
||||
This accomodation (instead of requiring a :doc:`xo::qty::natural_unit<natural-unit-class>` instance
|
||||
is to make possible code like this possible:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include "xo/unit/quantity.hpp"
|
||||
|
||||
using namespace xo::qty;
|
||||
|
||||
quantity<u::meter / u::second> x;
|
||||
quantity<u::meter * u::mter> y;
|
||||
|
||||
while rejecting attempt to mix multiple scales in the same quantity value:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
quantity<u::meter * u::millimeter> x; // will not compile
|
||||
|
||||
Class
|
||||
-----
|
||||
|
||||
The primary data structure for interacting with xo-unit is the
|
||||
template class ``xo::qty::quantity``.
|
||||
A quantity is a compile-time wrapper around a single arithmetic value,
|
||||
with type taken from the ``Repr`` parameter in ``quantity<Unit, Repr>``.
|
||||
|
||||
.. doxygenclass:: xo::qty::quantity
|
||||
|
||||
Member Variables
|
||||
----------------
|
||||
|
||||
.. doxygengroup:: quantity-static-vars
|
||||
.. doxygengroup:: quantity-instance-vars
|
||||
|
||||
Type Traits
|
||||
-----------
|
||||
|
||||
.. doxygengroup:: quantity-type-traits
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. doxygengroup:: quantity-ctors
|
||||
|
||||
The simplest way to create a quantity instance is to use either
|
||||
|
||||
* factory functions in ``xo::qty::qty``, see :doc:`quantity-factoryfunctions`
|
||||
* unit variables in ``xo::qty::qty``, see :doc:`quantity-unitvars`
|
||||
|
||||
Assignment
|
||||
----------
|
||||
|
||||
.. doxygengroup:: quantity-assignment
|
||||
|
||||
Access Methods
|
||||
--------------
|
||||
|
||||
.. doxygengroup:: quantity-access-methods
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. doxygengroup:: quantity-constants
|
||||
|
||||
Conversion Methods
|
||||
------------------
|
||||
|
||||
Amount-preserving conversion to quantities with different units and/or representation.
|
||||
|
||||
.. doxygengroup:: quantity-unit-conversion
|
||||
|
||||
Arithmetic
|
||||
----------
|
||||
|
||||
.. doxygengroup:: quantity-operators
|
||||
|
||||
Support methods for arithmetic operations
|
||||
|
||||
.. doxygengroup:: quantity-arithmetic-support
|
||||
|
||||
Comparison
|
||||
----------
|
||||
|
||||
Support methods for comparison operators
|
||||
|
||||
.. doxygengroup:: quantity-comparison-support
|
||||
94
xo-unit/docs/quantity-factoryfunctions.rst
Normal file
94
xo-unit/docs/quantity-factoryfunctions.rst
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
.. _quantity_factoryfunctions:
|
||||
|
||||
Quantity Factory Functions
|
||||
==========================
|
||||
|
||||
Convenience functions for creating quantities with compile-time units
|
||||
|
||||
Context
|
||||
-------
|
||||
|
||||
.. ditaa::
|
||||
:--scale: 0.85
|
||||
|
||||
+----------------+---------------+
|
||||
|cBLU quantity | xquantity |
|
||||
+----------------+---------------+
|
||||
| scaled_unit |
|
||||
+--------------------------------+
|
||||
| natural_unit |
|
||||
+--------------------------------+
|
||||
| bpu |
|
||||
+----------------+ |
|
||||
| bu_store | |
|
||||
+----------------+---------------+
|
||||
| basis_unit |
|
||||
+--------------------------------+
|
||||
| dimension |
|
||||
+--------------------------------+
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <xo/unit/quantity.hpp>
|
||||
|
||||
Mass
|
||||
----
|
||||
.. doxygenfunction:: xo::qty::qty::picograms
|
||||
.. doxygenfunction:: xo::qty::qty::nanograms
|
||||
.. doxygenfunction:: xo::qty::qty::micrograms
|
||||
.. doxygenfunction:: xo::qty::qty::milligrams
|
||||
.. doxygenfunction:: xo::qty::qty::grams
|
||||
.. doxygenfunction:: xo::qty::qty::kilograms
|
||||
.. doxygenfunction:: xo::qty::qty::tonnes
|
||||
.. doxygenfunction:: xo::qty::qty::kilotonnes
|
||||
.. doxygenfunction:: xo::qty::qty::megatonnes
|
||||
.. doxygenfunction:: xo::qty::qty::gigatonnes
|
||||
|
||||
Distance
|
||||
--------
|
||||
.. doxygenfunction:: xo::qty::qty::picometers
|
||||
.. doxygenfunction:: xo::qty::qty::nanometers
|
||||
.. doxygenfunction:: xo::qty::qty::micrometers
|
||||
.. doxygenfunction:: xo::qty::qty::millimeters
|
||||
.. doxygenfunction:: xo::qty::qty::meters
|
||||
.. doxygenfunction:: xo::qty::qty::kilometers
|
||||
.. doxygenfunction:: xo::qty::qty::megameters
|
||||
.. doxygenfunction:: xo::qty::qty::gigameters
|
||||
|
||||
.. doxygenfunction:: xo::qty::qty::lightseconds
|
||||
.. doxygenfunction:: xo::qty::qty::astronomicalunits
|
||||
|
||||
.. doxygenfunction:: xo::qty::qty::inches
|
||||
.. doxygenfunction:: xo::qty::qty::feet
|
||||
.. doxygenfunction:: xo::qty::qty::yards
|
||||
.. doxygenfunction:: xo::qty::qty::miles
|
||||
|
||||
Time
|
||||
----
|
||||
.. doxygenfunction:: xo::qty::qty::picoseconds
|
||||
.. doxygenfunction:: xo::qty::qty::nanoseconds
|
||||
.. doxygenfunction:: xo::qty::qty::microseconds
|
||||
.. doxygenfunction:: xo::qty::qty::milliseconds
|
||||
.. doxygenfunction:: xo::qty::qty::seconds
|
||||
.. doxygenfunction:: xo::qty::qty::minutes
|
||||
.. doxygenfunction:: xo::qty::qty::hours
|
||||
.. doxygenfunction:: xo::qty::qty::days
|
||||
.. doxygenfunction:: xo::qty::qty::weeks
|
||||
.. doxygenfunction:: xo::qty::qty::months
|
||||
.. doxygenfunction:: xo::qty::qty::years
|
||||
.. doxygenfunction:: xo::qty::qty::year250s
|
||||
.. doxygenfunction:: xo::qty::qty::year360s
|
||||
.. doxygenfunction:: xo::qty::qty::year365s
|
||||
|
||||
Volatility
|
||||
----------
|
||||
.. doxygenfunction:: xo::qty::qty::volatility_30d
|
||||
.. doxygenfunction:: xo::qty::qty::volatility_250d
|
||||
.. doxygenfunction:: xo::qty::qty::volatility_360d
|
||||
.. doxygenfunction:: xo::qty::qty::volatility_365d
|
||||
31
xo-unit/docs/quantity-reference.rst
Normal file
31
xo-unit/docs/quantity-reference.rst
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
.. _quantity-reference:
|
||||
|
||||
Quantity Reference
|
||||
==================
|
||||
|
||||
.. ditaa::
|
||||
:--scale: 0.85
|
||||
|
||||
+----------------+---------------+
|
||||
|cBLU quantity | xquantity |
|
||||
+----------------+---------------+
|
||||
| scaled_unit |
|
||||
+--------------------------------+
|
||||
| natural_unit |
|
||||
+--------------------------------+
|
||||
| bpu |
|
||||
+----------------+ |
|
||||
| bu_store | |
|
||||
+----------------+---------------+
|
||||
| basis_unit |
|
||||
+--------------------------------+
|
||||
| dimension |
|
||||
+--------------------------------+
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
quantity-class
|
||||
quantity-factoryfunctions
|
||||
quantity-unitvars
|
||||
quantity-source-code
|
||||
11
xo-unit/docs/quantity-source-code.rst
Normal file
11
xo-unit/docs/quantity-source-code.rst
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
.. _quantity-source-code:
|
||||
|
||||
Quantity Source Code
|
||||
====================
|
||||
|
||||
github: `quantity.hpp @github`_
|
||||
|
||||
.. _`quantity.hpp @github`: https://github.com/rconybea/xo-unit/blob/main/include/xo/unit/quantity.hpp
|
||||
|
||||
.. literalinclude:: ../include/xo/unit/quantity.hpp
|
||||
:language: c++
|
||||
98
xo-unit/docs/quantity-unitvars.rst
Normal file
98
xo-unit/docs/quantity-unitvars.rst
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
.. _quantity-unitvars:
|
||||
|
||||
Quantity Unit Variables
|
||||
=======================
|
||||
|
||||
Built-in unit quantities
|
||||
|
||||
Context
|
||||
-------
|
||||
|
||||
.. ditaa::
|
||||
:--scale: 0.85
|
||||
|
||||
+----------------+---------------+
|
||||
|cBLU quantity | xquantity |
|
||||
+----------------+---------------+
|
||||
| scaled_unit |
|
||||
+--------------------------------+
|
||||
| natural_unit |
|
||||
+--------------------------------+
|
||||
| bpu |
|
||||
+----------------+ |
|
||||
| bu_store | |
|
||||
+----------------+---------------+
|
||||
| basis_unit |
|
||||
+--------------------------------+
|
||||
| dimension |
|
||||
+--------------------------------+
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <xo/unit/quantity.hpp>
|
||||
|
||||
The ``xo::qty::qty`` namespace contains unit quantities in each dimension.
|
||||
Can use these to assemble unit quantities with compound dimensions
|
||||
|
||||
.. code-block:: cpp
|
||||
:linenos:
|
||||
:emphasize-lines: 6
|
||||
|
||||
#include "xo/unit/quantity.hpp"
|
||||
|
||||
namespace q = xo::qty::qty;
|
||||
|
||||
auto q1 = (q::kilometers(150.0) / q::hours(0.5));
|
||||
constexpr auto u_mps = q:meter / q:second;
|
||||
auto q2 = with_units_from(q1, u_mps);
|
||||
|
||||
|
||||
Mass
|
||||
----
|
||||
.. doxygenvariable:: xo::qty::qty::picogram
|
||||
.. doxygenvariable:: xo::qty::qty::nanogram
|
||||
.. doxygenvariable:: xo::qty::qty::microgram
|
||||
.. doxygenvariable:: xo::qty::qty::milligram
|
||||
.. doxygenvariable:: xo::qty::qty::gram
|
||||
.. doxygenvariable:: xo::qty::qty::kilogram
|
||||
.. doxygenvariable:: xo::qty::qty::tonne
|
||||
.. doxygenvariable:: xo::qty::qty::kilotonne
|
||||
.. doxygenvariable:: xo::qty::qty::megatonne
|
||||
.. doxygenvariable:: xo::qty::qty::gigatonne
|
||||
|
||||
Distance
|
||||
--------
|
||||
.. doxygenvariable:: xo::qty::qty::picometer
|
||||
.. doxygenvariable:: xo::qty::qty::nanometer
|
||||
.. doxygenvariable:: xo::qty::qty::micrometer
|
||||
.. doxygenvariable:: xo::qty::qty::millimeter
|
||||
.. doxygenvariable:: xo::qty::qty::meter
|
||||
.. doxygenvariable:: xo::qty::qty::kilometer
|
||||
.. doxygenvariable:: xo::qty::qty::megameter
|
||||
.. doxygenvariable:: xo::qty::qty::gigameter
|
||||
.. doxygenvariable:: xo::qty::qty::lightsecond
|
||||
.. doxygenvariable:: xo::qty::qty::astronomicalunit
|
||||
.. doxygenvariable:: xo::qty::qty::inch
|
||||
.. doxygenvariable:: xo::qty::qty::foot
|
||||
.. doxygenvariable:: xo::qty::qty::yard
|
||||
.. doxygenvariable:: xo::qty::qty::mile
|
||||
|
||||
Time
|
||||
----
|
||||
.. doxygenvariable:: xo::qty::qty::picosecond
|
||||
.. doxygenvariable:: xo::qty::qty::nanosecond
|
||||
.. doxygenvariable:: xo::qty::qty::microsecond
|
||||
.. doxygenvariable:: xo::qty::qty::millisecond
|
||||
.. doxygenvariable:: xo::qty::qty::second
|
||||
.. doxygenvariable:: xo::qty::qty::minute
|
||||
.. doxygenvariable:: xo::qty::qty::hour
|
||||
.. doxygenvariable:: xo::qty::qty::day
|
||||
.. doxygenvariable:: xo::qty::qty::week
|
||||
.. doxygenvariable:: xo::qty::qty::month
|
||||
.. doxygenvariable:: xo::qty::qty::year
|
||||
.. doxygenvariable:: xo::qty::qty::year250
|
||||
.. doxygenvariable:: xo::qty::qty::year360
|
||||
.. doxygenvariable:: xo::qty::qty::year365
|
||||
165
xo-unit/docs/scaled-unit-class.rst
Normal file
165
xo-unit/docs/scaled-unit-class.rst
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
.. _scaled-unit-class:
|
||||
|
||||
Scaled Unit
|
||||
===========
|
||||
|
||||
A dimensionless multiple of a :doc:`natural_unit<natural-unit-class>`
|
||||
|
||||
Context
|
||||
-------
|
||||
|
||||
.. ditaa::
|
||||
:--scale: 0.85
|
||||
|
||||
+----------------+----------------+
|
||||
| quantity | xquantity |
|
||||
+----------------+----------------+
|
||||
|cBLU scaled_unit |
|
||||
+---------------------------------+
|
||||
| natural_unit |
|
||||
+---------------------------------+
|
||||
| bpu |
|
||||
+----------------+ |
|
||||
| bu_store | |
|
||||
+----------------+----------------+
|
||||
| basis_unit |
|
||||
+---------------------------------+
|
||||
| dimension |
|
||||
+---------------------------------+
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
.. code-block::cpp
|
||||
|
||||
#include <xo/unit/scaled_unit.hpp>
|
||||
|
||||
Extension of :doc:`natural_unit<natural-unit-class>` to enable representing the intermediate
|
||||
result of multiplication (or division) of natural units.
|
||||
|
||||
- represents a (dimensionless) multiple of a cartesian product of basis units.
|
||||
- constexpr implementation
|
||||
- limited support for fractional dimensions such as time^-1/2
|
||||
|
||||
.. uml::
|
||||
:caption: scaled unit after (u::meter * u::foot / u::minute)
|
||||
:scale: 99%
|
||||
:align: center
|
||||
|
||||
object area_per_time<<scaled_unit>>
|
||||
area_per_time : outer_scale_factor = 3048/10000
|
||||
area_per_time : outer_scale_sq = 1.0
|
||||
area_per_time : natural_unit = m2_per_min
|
||||
|
||||
object m2_per_min<<natural_unit>>
|
||||
m2_per_min : n_bpu = 2
|
||||
m2_per_min : bpu_v[]
|
||||
|
||||
object m2<<bpu>>
|
||||
m2 : native_dim = dim::distance
|
||||
m2 : scalefactor = 1/1
|
||||
m2 : power = 2/1
|
||||
|
||||
object min<<bpu>>
|
||||
min : native_dim = dim::time
|
||||
min : scalefactor = 60/1
|
||||
min : power = -1/1
|
||||
|
||||
area_per_time o-- m2_per_min
|
||||
m2_per_min o-- m2
|
||||
m2_per_min o-- min
|
||||
|
||||
Scaled units with non-unity outer scalefactors arise as intermediate results
|
||||
of quantity arithmetic
|
||||
|
||||
Motivation
|
||||
^^^^^^^^^^
|
||||
|
||||
Consider multiplying two units:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
using namespace xo::qty;
|
||||
|
||||
constexpr auto u_prod = u::meter * u::kilometer;
|
||||
|
||||
How should we represent the product?
|
||||
|
||||
We don't want to mix units. Instead we consolidate on a common unit;
|
||||
to do this we accumulate a product of conversion factors from such consolidation.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: cpp
|
||||
:emphasize-lines: 3
|
||||
|
||||
static_assert(u_prod.n_bpu() == 1);
|
||||
static_assert(u_prod[0].bu() == detail::bu::meter);
|
||||
static_assert(u_prod[0].power() == power_ratio_type(2));
|
||||
static_assert(u_prod.outer_scale_factor_ == xo::ratio::ratio<int64_t>(1000));
|
||||
static_assert(u_prod.outer_scale_sq_ == 1.0); // used if fractional dimension
|
||||
|
||||
Here we accumulate :code:`1000`, from converting kilometers to meters.
|
||||
|
||||
Division works similarly. In this example dimension cancel, but we still have a non-unity conversion factor.
|
||||
|
||||
.. code-block:: cpp
|
||||
:emphasize-lines: 7
|
||||
|
||||
namespace u = xo::qty::u;
|
||||
|
||||
constexpr auto u_div = u::meter / u::kilometer;
|
||||
|
||||
// dimensionlesss result
|
||||
static_assert(u_prod.n_bpu() == 0);
|
||||
static_assert(u_prod.outer_scale_factor_ == xo::ratio::ratio<int64_t>(1,1000));
|
||||
static_assert(u_prod.outer_scale_sq_ == 1.0);
|
||||
|
||||
When multiple dimensions needing conversion are involved, scalefactors accumulate:
|
||||
|
||||
.. code-block:: cpp
|
||||
:emphasize-lines: 8
|
||||
|
||||
namespace u = xo::qty::u;
|
||||
|
||||
constexpr auto u2_prod = u::meter * u::hour * u::kilometer * u::minute;
|
||||
|
||||
static_assert(u2_prod.n_bpu() == 2);
|
||||
static_assert(u2_prod[0].bu() == detail::bu::meter);
|
||||
static_assert(u2_prod[1].bu() == detail::bu::hour);
|
||||
static_assert(u2_prod.outer_scale_factor_ == xo::ratio::ratio<int64_t>(50,3));
|
||||
static_assert(u2_prod.outer_scale_sq_ == 1.0); // used if fractional dimension
|
||||
|
||||
Here the :code:`50/3` result comes from multiplying :code:`1000/1` (converting kilometers -> meters)
|
||||
by :code:`1/60` (converting minutes -> hours)
|
||||
|
||||
|
||||
Class
|
||||
-----
|
||||
|
||||
.. doxygenclass:: xo::qty::scaled_unit
|
||||
|
||||
Member Variables
|
||||
----------------
|
||||
|
||||
.. doxygengroup:: scaled-unit-instance-vars
|
||||
|
||||
Type Traits
|
||||
-----------
|
||||
|
||||
.. doxygengroup:: scaled-unit-type-traits
|
||||
|
||||
Access Methods
|
||||
--------------
|
||||
|
||||
.. doxygengroup:: scaled-unit-access-methods
|
||||
|
||||
General Methods
|
||||
---------------
|
||||
|
||||
.. doxygengroup:: scaled-unit-general-methods
|
||||
|
||||
Operators
|
||||
---------
|
||||
|
||||
.. doxygengroup:: scaled-unit-operators
|
||||
75
xo-unit/docs/scaled-unit-constants.rst
Normal file
75
xo-unit/docs/scaled-unit-constants.rst
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
.. _scaled-unit-constants
|
||||
|
||||
Scaled Unit Constants
|
||||
=====================
|
||||
|
||||
Built-in unit constants, for use with conversions
|
||||
|
||||
Context
|
||||
-------
|
||||
|
||||
.. ditaa::
|
||||
:--scale: 0.85
|
||||
|
||||
+----------------+---------------+
|
||||
| quantity | xquantity |
|
||||
+----------------+---------------+
|
||||
|cBLU scaled_unit |
|
||||
+--------------------------------+
|
||||
| natural_unit |
|
||||
+--------------------------------+
|
||||
| bpu |
|
||||
+----------------+ |
|
||||
| bu_store | |
|
||||
+----------------+---------------+
|
||||
| basis_unit |
|
||||
+--------------------------------+
|
||||
| dimension |
|
||||
+--------------------------------+
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Built-in units. Application code may use these to trigger conversion
|
||||
|
||||
.. code-block:: cpp
|
||||
:emphasize-lines: 5
|
||||
|
||||
#include <xo/unit/quantity.hpp>
|
||||
|
||||
using namespace xo::qty;
|
||||
|
||||
constexpr quantity<u::meter / u::second> q1 = q::miles(60) / q::hour;
|
||||
|
||||
Note that it's often easiest to use :doc:`unit quantity constants<quantity-unitvars>`,
|
||||
like :code:`q::hour` in the example above
|
||||
|
||||
Dimensionless Constant
|
||||
----------------------
|
||||
|
||||
.. doxygengroup:: scaled-unit-dimensionless
|
||||
|
||||
Mass Units
|
||||
----------
|
||||
|
||||
.. doxygengroup:: scaled-unit-mass
|
||||
|
||||
Distance Units
|
||||
--------------
|
||||
|
||||
.. doxygengroup:: scaled-unit-distance
|
||||
|
||||
Time Units
|
||||
----------
|
||||
|
||||
.. doxygengroup:: scaled-unit-time
|
||||
|
||||
Volatility Units
|
||||
----------------
|
||||
|
||||
.. doxygengroup:: scaled-unit-volatility
|
||||
|
||||
Miscellaneous Units
|
||||
-------------------
|
||||
|
||||
.. doxygengroup:: scaled-unit-misc
|
||||
31
xo-unit/docs/scaled-unit-reference.rst
Normal file
31
xo-unit/docs/scaled-unit-reference.rst
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
.. _scaled-unit-reference:
|
||||
|
||||
Scaled Unit Reference
|
||||
=====================
|
||||
|
||||
A dimensionless multiple of a :doc:`natural_unit<natural-unit-class>`
|
||||
|
||||
.. ditaa::
|
||||
:--scale: 0.85
|
||||
|
||||
+----------------+---------------+
|
||||
| quantity | xquantity |
|
||||
+----------------+---------------+
|
||||
|cBLU scaled_unit |
|
||||
+--------------------------------+
|
||||
| natural_unit |
|
||||
+--------------------------------+
|
||||
| bpu |
|
||||
+----------------+ |
|
||||
| bu_store | |
|
||||
+----------------+---------------+
|
||||
| basis_unit |
|
||||
+--------------------------------+
|
||||
| dimension |
|
||||
+--------------------------------+
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
Scaled Unit Class <scaled-unit-class>
|
||||
scaled-unit-constants
|
||||
9
xo-unit/docs/ubuntu-github-workflow.rst
Normal file
9
xo-unit/docs/ubuntu-github-workflow.rst
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
.. ubuntu-github-workflow:
|
||||
|
||||
Ubuntu Github Workflow
|
||||
======================
|
||||
|
||||
Instructions for build starting on a stock ubuntu platform (see `xo-unit/.github/workflows/ubuntu_main.yml`)
|
||||
|
||||
.. literalinclude:: ../.github/workflows/ubuntu-main.yml
|
||||
:language: yaml
|
||||
96
xo-unit/docs/xquantity-class.rst
Normal file
96
xo-unit/docs/xquantity-class.rst
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
.. _xquantity-class:
|
||||
|
||||
Xquantity
|
||||
=========
|
||||
|
||||
Polymorphic dimensioned quantity with runtime unit checking/conversion
|
||||
|
||||
Context
|
||||
-------
|
||||
|
||||
.. ditaa::
|
||||
:--scale: 0.85
|
||||
|
||||
+----------------+---------------+
|
||||
| quantity |cBLU xquantity |
|
||||
+----------------+---------------+
|
||||
| scaled_unit |
|
||||
+--------------------------------+
|
||||
| natural_unit |
|
||||
+--------------------------------+
|
||||
| bpu |
|
||||
+----------------+ |
|
||||
| bu_store | |
|
||||
+----------------+---------------+
|
||||
| basis_unit |
|
||||
+--------------------------------+
|
||||
| dimension |
|
||||
+--------------------------------+
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <xo/unit/xquantity.hpp>
|
||||
|
||||
.. uml::
|
||||
:scale: 99%
|
||||
:align: center
|
||||
|
||||
allowmixing
|
||||
|
||||
object qty1<<xquantity>>
|
||||
qty1 : scale = 1.23
|
||||
qty1 : unit = unit
|
||||
|
||||
object unit<<scaled_unit>>
|
||||
unit : is_natural() = true
|
||||
|
||||
qty1 o-- unit
|
||||
|
||||
|
||||
Class
|
||||
-----
|
||||
|
||||
Class with run-time unit representation.
|
||||
|
||||
.. doxygenclass:: xo::qty::xquantity
|
||||
|
||||
Member Variables
|
||||
----------------
|
||||
|
||||
.. doxygengroup:: xquantity-instance-vars
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. doxygengroup:: xquantity-ctors
|
||||
|
||||
Access Methods
|
||||
--------------
|
||||
|
||||
.. doxygengroup:: xquantity-access-methods
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. doxygengroup:: xquantity-constants
|
||||
|
||||
Conversion Methods
|
||||
------------------
|
||||
|
||||
.. doxygengroup:: xquantity-unit-conversion
|
||||
|
||||
Arithmetic
|
||||
----------
|
||||
|
||||
.. doxygengroup:: xquantity-operators
|
||||
|
||||
Support methods for arithmetic operations
|
||||
|
||||
.. doxygengroup:: xquantity-arithmetic-support
|
||||
|
||||
Comparison
|
||||
----------
|
||||
|
||||
Support methods for comparison operators
|
||||
|
||||
.. doxygengroup:: xquantity-comparison-support
|
||||
29
xo-unit/docs/xquantity-reference.rst
Normal file
29
xo-unit/docs/xquantity-reference.rst
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
.. _xquantity-reference:
|
||||
|
||||
Xquantity Reference
|
||||
===================
|
||||
|
||||
.. ditaa::
|
||||
:--scale: 0.85
|
||||
|
||||
+----------------+---------------+
|
||||
| quantity |cBLU xquantity |
|
||||
+----------------+---------------+
|
||||
| scaled_unit |
|
||||
+--------------------------------+
|
||||
| natural_unit |
|
||||
+--------------------------------+
|
||||
| bpu |
|
||||
+----------------+ |
|
||||
| bu_store | |
|
||||
+----------------+---------------+
|
||||
| basis_unit |
|
||||
+--------------------------------+
|
||||
| dimension |
|
||||
+--------------------------------+
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
xquantity-class
|
||||
xquantity-source-code
|
||||
11
xo-unit/docs/xquantity-source-code.rst
Normal file
11
xo-unit/docs/xquantity-source-code.rst
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
.. _xquantity-source-code:
|
||||
|
||||
Xquantity Source Code
|
||||
=====================
|
||||
|
||||
github: `xquantity.hpp @github`_
|
||||
|
||||
.. _`xquantity.hpp @github`: https://github.com/rconybea/xo-unit/blob/main/include/xo/unit/xquantity.hpp
|
||||
|
||||
.. literalinclude:: ../include/xo/unit/xquantity.hpp
|
||||
:language: c++
|
||||
10
xo-unit/example/CMakeLists.txt
Normal file
10
xo-unit/example/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
add_subdirectory(ex1)
|
||||
add_subdirectory(ex2)
|
||||
add_subdirectory(ex3)
|
||||
add_subdirectory(ex4)
|
||||
add_subdirectory(ex5)
|
||||
add_subdirectory(ex6)
|
||||
add_subdirectory(ex7)
|
||||
add_subdirectory(ex8)
|
||||
add_subdirectory(ex_su)
|
||||
add_subdirectory(ex_qty)
|
||||
12
xo-unit/example/ex1/CMakeLists.txt
Normal file
12
xo-unit/example/ex1/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# xo-unit/example/ex1/CMakeLists.txt
|
||||
|
||||
set(SELF_EXE xo_unit_ex1)
|
||||
set(SELF_SRCS ex1.cpp)
|
||||
|
||||
if (XO_ENABLE_EXAMPLES)
|
||||
xo_add_executable(${SELF_EXE} ${SELF_SRCS})
|
||||
xo_self_headeronly_dependency(${SELF_EXE} xo_unit)
|
||||
xo_dependency(${SELF_EXE} xo_flatstring)
|
||||
endif()
|
||||
|
||||
# end CMakeLists.txt
|
||||
53
xo-unit/example/ex1/ex1.cpp
Normal file
53
xo-unit/example/ex1/ex1.cpp
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/** @file ex1.cpp **/
|
||||
|
||||
#include "xo/unit/quantity.hpp"
|
||||
#include "xo/unit/quantity_iostream.hpp"
|
||||
#include <iostream>
|
||||
|
||||
int
|
||||
main () {
|
||||
namespace q = xo::qty::qty;
|
||||
namespace u = xo::qty::u;
|
||||
using xo::qty::quantity;
|
||||
using xo::flatstring;
|
||||
using namespace std;
|
||||
|
||||
constexpr auto t = q::minutes(2);
|
||||
constexpr auto d = q::kilometers(2.5);
|
||||
|
||||
constexpr auto t2 = t*t;
|
||||
constexpr auto a = d / (t*t);
|
||||
|
||||
cerr << "t: " << t << ", d: " << d
|
||||
<< ", t^2: " << t2
|
||||
<< ", d.t^-2: " << a
|
||||
<< endl;
|
||||
|
||||
static_assert(std::same_as<decltype(t)::repr_type, int>);
|
||||
static_assert(sizeof(t) == sizeof(int));
|
||||
static_assert(t.scale() == 2);
|
||||
static_assert(t.abbrev() == flatstring("min"));
|
||||
|
||||
static_assert(std::same_as<decltype(d)::repr_type, double>);
|
||||
static_assert(sizeof(d) == sizeof(double));
|
||||
static_assert(d.scale() == 2.5);
|
||||
static_assert(d.abbrev() == flatstring("km"));
|
||||
|
||||
static_assert(std::same_as<decltype(t2)::repr_type, int>);
|
||||
static_assert(sizeof(t2) == sizeof(int));
|
||||
static_assert(t2.scale() == 4);
|
||||
static_assert(t2.abbrev() == flatstring("min^2"));
|
||||
|
||||
static_assert(std::same_as<decltype(a)::repr_type, double>);
|
||||
static_assert(sizeof(a) == sizeof(double));
|
||||
static_assert(a.scale() == 0.625);
|
||||
static_assert(a.abbrev() == flatstring("km.min^-2"));
|
||||
|
||||
constexpr auto a2 = a.rescale_ext<(u::meter / (u::second * u::second))>();
|
||||
|
||||
cerr << "d.t^-2: " << a2 << endl;
|
||||
|
||||
static_assert(a2.abbrev() == flatstring("m.s^-2"));
|
||||
}
|
||||
|
||||
/** end ex1.cpp **/
|
||||
12
xo-unit/example/ex2/CMakeLists.txt
Normal file
12
xo-unit/example/ex2/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# xo-unit/example/ex2/CMakeLists.txt
|
||||
|
||||
set(SELF_EXE xo_unit_ex2)
|
||||
set(SELF_SRCS ex2.cpp)
|
||||
|
||||
if (XO_ENABLE_EXAMPLES)
|
||||
xo_add_executable(${SELF_EXE} ${SELF_SRCS})
|
||||
xo_self_headeronly_dependency(${SELF_EXE} xo_unit)
|
||||
xo_dependency(${SELF_EXE} xo_flatstring)
|
||||
endif()
|
||||
|
||||
# end CMakeLists.txt
|
||||
49
xo-unit/example/ex2/ex2.cpp
Normal file
49
xo-unit/example/ex2/ex2.cpp
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/** @file ex2.cpp **/
|
||||
|
||||
#include "xo/unit/quantity.hpp"
|
||||
#include "xo/unit/quantity_iostream.hpp"
|
||||
#include <iostream>
|
||||
|
||||
int
|
||||
main () {
|
||||
namespace q = xo::qty::qty;
|
||||
namespace u = xo::qty::u;
|
||||
using xo::qty::with_units_from;
|
||||
using xo::qty::with_units;
|
||||
using xo::qty::quantity;
|
||||
using xo::flatstring;
|
||||
using namespace std;
|
||||
|
||||
constexpr auto t = q::minutes(2);
|
||||
constexpr auto d = q::kilometers(2.5);
|
||||
|
||||
constexpr auto t2 = t*t;
|
||||
constexpr auto a = d / (t*t);
|
||||
|
||||
cerr << "t: " << t << ", d: " << d
|
||||
<< ", t^2: " << t2
|
||||
<< ", d.t^-2: " << a
|
||||
<< endl;
|
||||
|
||||
constexpr auto a2 = a.rescale_ext<u::meter / (u::second * u::second)>();
|
||||
|
||||
static_assert(a2.abbrev() == flatstring("m.s^-2"));
|
||||
|
||||
cerr << "a2: " << a2 << endl;
|
||||
|
||||
constexpr auto a3 = with_units<u::meter / (u::second * u::second)>(a);
|
||||
|
||||
static_assert(a3.abbrev() == flatstring("m.s^-2"));
|
||||
|
||||
cerr << "a3: " << a3 << endl;
|
||||
|
||||
constexpr auto au = q::meter / (q::second * q::second);
|
||||
constexpr auto a4 = with_units_from(a, au);
|
||||
|
||||
static_assert(a4.abbrev() == flatstring("m.s^-2"));
|
||||
|
||||
cerr << "a4: " << a4 << endl;
|
||||
}
|
||||
|
||||
|
||||
/** end ex2.cpp **/
|
||||
12
xo-unit/example/ex3/CMakeLists.txt
Normal file
12
xo-unit/example/ex3/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# xo-unit/example/ex3/CMakeLists.txt
|
||||
|
||||
set(SELF_EXE xo_unit_ex3)
|
||||
set(SELF_SRCS ex3.cpp)
|
||||
|
||||
if (XO_ENABLE_EXAMPLES)
|
||||
xo_add_executable(${SELF_EXE} ${SELF_SRCS})
|
||||
xo_self_headeronly_dependency(${SELF_EXE} xo_unit)
|
||||
xo_dependency(${SELF_EXE} xo_flatstring)
|
||||
endif()
|
||||
|
||||
# end CMakeLists.txt
|
||||
25
xo-unit/example/ex3/ex3.cpp
Normal file
25
xo-unit/example/ex3/ex3.cpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/** @file ex3.cpp **/
|
||||
|
||||
#include "xo/unit/quantity.hpp"
|
||||
#include "xo/unit/quantity_iostream.hpp"
|
||||
#include <iostream>
|
||||
|
||||
int
|
||||
main () {
|
||||
namespace q = xo::qty::qty;
|
||||
namespace u = xo::qty::u;
|
||||
using xo::qty::quantity;
|
||||
using namespace std;
|
||||
|
||||
constexpr quantity<u::second> t = q::minutes(2);
|
||||
constexpr quantity<u::meter> d = q::kilometers(2.5);
|
||||
|
||||
constexpr auto t2 = t*t;
|
||||
constexpr auto a = d / (t*t);
|
||||
|
||||
cerr << "t: " << t << ", d: " << d
|
||||
<< ", d.t^-2: " << a
|
||||
<< endl;
|
||||
}
|
||||
|
||||
/** end ex3.cpp **/
|
||||
12
xo-unit/example/ex4/CMakeLists.txt
Normal file
12
xo-unit/example/ex4/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# xo-unit/example/ex4/CMakeLists.txt
|
||||
|
||||
set(SELF_EXE xo_unit_ex4)
|
||||
set(SELF_SRCS ex4.cpp)
|
||||
|
||||
if (XO_ENABLE_EXAMPLES)
|
||||
xo_add_executable(${SELF_EXE} ${SELF_SRCS})
|
||||
xo_self_headeronly_dependency(${SELF_EXE} xo_unit)
|
||||
xo_dependency(${SELF_EXE} xo_flatstring)
|
||||
endif()
|
||||
|
||||
# end CMakeLists.txt
|
||||
30
xo-unit/example/ex4/ex4.cpp
Normal file
30
xo-unit/example/ex4/ex4.cpp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/** @file ex4.cpp **/
|
||||
|
||||
#include "xo/unit/quantity.hpp"
|
||||
#include "xo/unit/quantity_iostream.hpp"
|
||||
#include <iostream>
|
||||
|
||||
int
|
||||
main () {
|
||||
namespace q = xo::qty::qty;
|
||||
|
||||
auto t1 = q::milliseconds(1);
|
||||
auto t2 = q::minutes(1);
|
||||
|
||||
auto r1 = t1 / with_repr<double>(t2);
|
||||
|
||||
static_assert(r1.is_dimensionless());
|
||||
static_assert(!t2.is_dimensionless());
|
||||
|
||||
static_assert(std::same_as<decltype(static_cast<double>(r1)), double>);
|
||||
|
||||
/* r1_value: assignment compiles, since r1 dimensionless */
|
||||
double r1_value = r1;
|
||||
|
||||
/* r2_value: assignment won't compile, 'cannot convert' error */
|
||||
//double r2_value = t2;
|
||||
|
||||
std::cerr << "t1: " << t1 << ", t2: " << t2 << ", t1/t2: " << r1 << std::endl;
|
||||
}
|
||||
|
||||
/** end ex4.cpp */
|
||||
12
xo-unit/example/ex5/CMakeLists.txt
Normal file
12
xo-unit/example/ex5/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# xo-unit/example/ex5/CMakeLists.txt
|
||||
|
||||
set(SELF_EXE xo_unit_ex5)
|
||||
set(SELF_SRCS ex5.cpp)
|
||||
|
||||
if (XO_ENABLE_EXAMPLES)
|
||||
xo_add_executable(${SELF_EXE} ${SELF_SRCS})
|
||||
xo_self_headeronly_dependency(${SELF_EXE} xo_unit)
|
||||
xo_dependency(${SELF_EXE} xo_flatstring)
|
||||
endif()
|
||||
|
||||
# end CMakeLists.txt
|
||||
24
xo-unit/example/ex5/ex5.cpp
Normal file
24
xo-unit/example/ex5/ex5.cpp
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/** @file ex5.cpp **/
|
||||
|
||||
#include "xo/unit/quantity.hpp"
|
||||
#include "xo/unit/quantity_iostream.hpp"
|
||||
#include <iostream>
|
||||
|
||||
int
|
||||
main () {
|
||||
//namespace u = xo::unit::units;
|
||||
namespace q = xo::qty::qty;
|
||||
using namespace std;
|
||||
|
||||
/* 20% volatility over 250 days (approx number of trading days in one year) */
|
||||
auto q1 = q::volatility_250d(0.2);
|
||||
/* 10% volatility over 30 days */
|
||||
auto q2 = q::volatility_30d(0.1);
|
||||
|
||||
auto sum = q1 + q2;
|
||||
auto prod = q1 * q2;
|
||||
|
||||
cerr << "q1: " << q1 << ", q2: " << q2 << ", q1+q2: " << sum << ", q1*q2: " << prod << endl;
|
||||
}
|
||||
|
||||
/** end ex5.cpp */
|
||||
12
xo-unit/example/ex6/CMakeLists.txt
Normal file
12
xo-unit/example/ex6/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# xo-unit/example/ex6/CMakeLists.txt
|
||||
|
||||
set(SELF_EXE xo_unit_ex6)
|
||||
set(SELF_SRCS ex6.cpp)
|
||||
|
||||
if (XO_ENABLE_EXAMPLES)
|
||||
xo_add_executable(${SELF_EXE} ${SELF_SRCS})
|
||||
xo_self_headeronly_dependency(${SELF_EXE} xo_unit)
|
||||
xo_dependency(${SELF_EXE} xo_flatstring)
|
||||
endif()
|
||||
|
||||
# end CMakeLists.txt
|
||||
36
xo-unit/example/ex6/ex6.cpp
Normal file
36
xo-unit/example/ex6/ex6.cpp
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/** @file ex6.cpp **/
|
||||
|
||||
#include "xo/unit/quantity.hpp"
|
||||
#include "xo/unit/quantity_iostream.hpp"
|
||||
#include <iostream>
|
||||
|
||||
int
|
||||
main () {
|
||||
using xo::qty::quantity;
|
||||
namespace q = xo::qty::qty;
|
||||
using xo::flatstring;
|
||||
|
||||
/* 20% volatility over 360 days */
|
||||
auto q1 = q::volatility_360d(0.2);
|
||||
/* 10% volatility over 30 days */
|
||||
auto q2 = q::volatility_30d(0.1);
|
||||
|
||||
/* 10% volatility per 30 days
|
||||
* ~ (10% * sqrt(360/30)) volatility over 360 days
|
||||
* ~ (10% * 3.4641)
|
||||
* ~ 0.34641yr360^(-1/2)
|
||||
*/
|
||||
|
||||
auto sum = q1 + q2;
|
||||
auto prod = q1 * q2;
|
||||
|
||||
static_assert(sum.abbrev() == flatstring("yr360^(-1/2)"));
|
||||
static_assert(prod.abbrev() == flatstring("yr360^-1"));
|
||||
|
||||
std::cerr << "q1: " << q1 << std::endl;
|
||||
std::cerr << "q2: " << q2 << std::endl;
|
||||
std::cerr << "q1+q2: " << sum << std::endl;
|
||||
std::cerr << "q1*q2: " << prod << std::endl;
|
||||
}
|
||||
|
||||
/** end ex6.cpp */
|
||||
12
xo-unit/example/ex7/CMakeLists.txt
Normal file
12
xo-unit/example/ex7/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# xo-unit/example/ex7/CMakeLists.txt
|
||||
|
||||
set(SELF_EXE xo_unit_ex7)
|
||||
set(SELF_SRCS ex7.cpp)
|
||||
|
||||
if (XO_ENABLE_EXAMPLES)
|
||||
xo_add_executable(${SELF_EXE} ${SELF_SRCS})
|
||||
xo_self_headeronly_dependency(${SELF_EXE} xo_unit)
|
||||
xo_dependency(${SELF_EXE} xo_flatstring)
|
||||
endif()
|
||||
|
||||
# end CMakeLists.txt
|
||||
31
xo-unit/example/ex7/ex7.cpp
Normal file
31
xo-unit/example/ex7/ex7.cpp
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/** @file ex7.cpp **/
|
||||
|
||||
#include "xo/unit/quantity.hpp"
|
||||
#include "xo/unit/quantity_iostream.hpp"
|
||||
#include <iostream>
|
||||
|
||||
int
|
||||
main () {
|
||||
using namespace xo::qty;
|
||||
namespace u = xo::qty::u;
|
||||
namespace q = xo::qty::qty;
|
||||
using namespace std;
|
||||
|
||||
quantity qty1 = 7.55 * q::kilometer / q::minute / q::minute;
|
||||
quantity qty2 = q::nanograms(123);
|
||||
quantity qty3 = qty2 * qty1;
|
||||
|
||||
cerr << "qty1: " << qty1 << endl;
|
||||
cerr << "qty2: " << qty2 << endl;
|
||||
cerr << "qty3: " << qty3 << endl;
|
||||
|
||||
/* rescale to not-so-absurd units */
|
||||
|
||||
/* kg.m.s^-2 */
|
||||
quantity res = qty3.rescale_ext<u::kilogram * u::meter / (u::second * u::second)>();
|
||||
|
||||
/* 2.57958e-10kg.m.s^-2 */
|
||||
cerr << "res: " << res << endl;
|
||||
}
|
||||
|
||||
/** end ex7.cpp */
|
||||
12
xo-unit/example/ex8/CMakeLists.txt
Normal file
12
xo-unit/example/ex8/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# xo-unit/example/ex8/CMakeLists.txt
|
||||
|
||||
set(SELF_EXE xo_unit_ex8)
|
||||
set(SELF_SRCS ex8.cpp)
|
||||
|
||||
if (XO_ENABLE_EXAMPLES)
|
||||
xo_add_executable(${SELF_EXE} ${SELF_SRCS})
|
||||
xo_self_headeronly_dependency(${SELF_EXE} xo_unit)
|
||||
xo_dependency(${SELF_EXE} xo_flatstring)
|
||||
endif()
|
||||
|
||||
# end CMakeLists.txt
|
||||
37
xo-unit/example/ex8/ex8.cpp
Normal file
37
xo-unit/example/ex8/ex8.cpp
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/** @file ex8.cpp **/
|
||||
|
||||
#include "xo/unit/xquantity.hpp"
|
||||
#include "xo/unit/xquantity_iostream.hpp"
|
||||
#include <iostream>
|
||||
|
||||
int
|
||||
main () {
|
||||
using namespace xo::qty;
|
||||
namespace u = xo::qty::u;
|
||||
using namespace std;
|
||||
|
||||
constexpr xquantity qty1(7, u::foot);
|
||||
constexpr xquantity qty2(6.0, u::inch);
|
||||
|
||||
// constexpr not supported for xquantity addition
|
||||
xquantity qty3 = qty1 + qty2;
|
||||
|
||||
cerr << "qty1: " << qty1 << endl;
|
||||
cerr << "qty2: " << qty2 << endl;
|
||||
cerr << "qty3: " << qty3 << endl;
|
||||
|
||||
/* rescale to mm */
|
||||
xquantity res = qty3.rescale_ext(xo::qty::u::millimeter);
|
||||
|
||||
/* 2286mm */
|
||||
cerr << "res: " << res << endl;
|
||||
|
||||
/* 12 */
|
||||
xquantity qty4 = qty1 / qty2;
|
||||
|
||||
auto res2 = qty4 + 4;
|
||||
|
||||
cerr << "res2: " << res << endl;
|
||||
}
|
||||
|
||||
/** end ex8.cpp */
|
||||
12
xo-unit/example/ex_qty/CMakeLists.txt
Normal file
12
xo-unit/example/ex_qty/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# xo-unit/example/ex_qty/CMakeLists.txt
|
||||
|
||||
set(SELF_EXE xo_unit_ex_qty)
|
||||
set(SELF_SRCS ex_qty.cpp)
|
||||
|
||||
if (XO_ENABLE_EXAMPLES)
|
||||
xo_add_executable(${SELF_EXE} ${SELF_SRCS})
|
||||
xo_self_headeronly_dependency(${SELF_EXE} xo_unit)
|
||||
xo_dependency(${SELF_EXE} xo_flatstring)
|
||||
endif()
|
||||
|
||||
# end CMakeLists.txt
|
||||
18
xo-unit/example/ex_qty/ex_qty.cpp
Normal file
18
xo-unit/example/ex_qty/ex_qty.cpp
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/* @file ex_qty.cpp */
|
||||
|
||||
#include "xo/unit/quantity.hpp"
|
||||
#include "xo/unit/quantity_iostream.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
int
|
||||
main() {
|
||||
using namespace xo::qty;
|
||||
namespace u = xo::qty::u;
|
||||
|
||||
static_assert(u::meter.n_bpu() == 1);
|
||||
|
||||
//constexpr auto q = qty::meters(2) + u::meter;
|
||||
}
|
||||
|
||||
/* end ex_qty.cpp */
|
||||
12
xo-unit/example/ex_su/CMakeLists.txt
Normal file
12
xo-unit/example/ex_su/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# xo-unit/example/su/CMakeLists.txt
|
||||
|
||||
set(SELF_EXE xo_unit_ex_su)
|
||||
set(SELF_SRCS ex_su.cpp)
|
||||
|
||||
if (XO_ENABLE_EXAMPLES)
|
||||
xo_add_executable(${SELF_EXE} ${SELF_SRCS})
|
||||
xo_self_headeronly_dependency(${SELF_EXE} xo_unit)
|
||||
xo_dependency(${SELF_EXE} xo_flatstring)
|
||||
endif()
|
||||
|
||||
# end CMakeLists.txt
|
||||
38
xo-unit/example/ex_su/ex_su.cpp
Normal file
38
xo-unit/example/ex_su/ex_su.cpp
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/** @file ex_su.cpp **/
|
||||
|
||||
#include "xo/unit/scaled_unit.hpp"
|
||||
#include "xo/unit/scaled_unit_iostream.hpp"
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
int
|
||||
main() {
|
||||
using namespace xo::qty;
|
||||
|
||||
constexpr auto u_prod = u::meter * u::kilometer;
|
||||
|
||||
static_assert(u_prod[0].bu() == detail::bu::meter);
|
||||
static_assert(u_prod[0].power() == power_ratio_type(2));
|
||||
static_assert(u_prod.outer_scale_factor_ == xo::ratio::ratio<int64_t>(1000));
|
||||
static_assert(u_prod.outer_scale_sq_ == 1.0); // used if fractional dimension
|
||||
|
||||
constexpr auto u_div = u::meter / u::kilometer;
|
||||
|
||||
static_assert(u_div.n_bpu() == 0);
|
||||
static_assert(u_div.outer_scale_factor_ == xo::ratio::ratio<int64_t>(1,1000));
|
||||
static_assert(u_prod.outer_scale_sq_ == 1.0); // used if fractional dimension
|
||||
|
||||
constexpr auto u2_prod = u::meter * u::hour * u::kilometer * u::minute;
|
||||
|
||||
static_assert(u2_prod.n_bpu() == 2);
|
||||
static_assert(u2_prod[0].bu() == detail::bu::meter);
|
||||
static_assert(u2_prod[1].bu() == detail::bu::hour);
|
||||
// *1000 from converting kilometers -> meters
|
||||
// /60 from converting minutes -> hours
|
||||
// 1000/60 = 50/3 in lowest terms
|
||||
static_assert(u2_prod.outer_scale_factor_ == xo::ratio::ratio<int64_t>(50,3)); // used if fractional dimension
|
||||
static_assert(u2_prod.outer_scale_sq_ == 1.0); // used if fractional dimension
|
||||
}
|
||||
|
||||
/** end ex_su.cpp **/
|
||||
299
xo-unit/flake.nix
Normal file
299
xo-unit/flake.nix
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
{
|
||||
description = "xo-unit: c++ compile-time dimension checking and unit conversion";
|
||||
|
||||
# Adapted from xo-nix2/flake.nix
|
||||
|
||||
# MANIFESTO
|
||||
# No build instructions in flake.nix
|
||||
# - Following Jade Lovelace's advice
|
||||
# - Build instructions are in pkgs/*.nix
|
||||
# - Each pkgs/*.nix is intended to work 'like a .nix file in nixpkgs'
|
||||
# I'm being lazy about source hashes, since flake.nix supplies them.
|
||||
#
|
||||
# Motivation (per JL) versus doing everything in flake.nix:
|
||||
# - nixpkgs-ready
|
||||
# - parameterized
|
||||
# - overridable
|
||||
# - still works if cross-compiling
|
||||
#
|
||||
# Instead: using flake.nix as entry point:
|
||||
# - pin nixpkgs to a specific revision, for reproducibility
|
||||
# - pin our candidate packages (pkgs/*.nix), for the same reason.
|
||||
|
||||
# to determine specific hash for nixpkgs:
|
||||
# 1. $ cd ~/proj/nixpkgs
|
||||
# 2. $ git checkout release-23.05
|
||||
# 3. $ git fetch
|
||||
# 4. $ git pull
|
||||
# 5. $ git log -1
|
||||
# take this hash, then substitue for ${hash} in:
|
||||
# inputs.nixpkgs.url = "https://github.com/NixOS/nixpkgs/archive/${hash}.tar.gz";
|
||||
# below
|
||||
#inputs.nixpkgs.url = "https://github.com/NixOS/nixpkgs/archive/9a333eaa80901efe01df07eade2c16d183761fa3.tar.gz";
|
||||
|
||||
# as sbove but instead of {release-23.05} use {release-23.11}
|
||||
# gcc -> 12.3.0
|
||||
# python -> 3.11.6
|
||||
#
|
||||
inputs.nixpkgs.url = "https://github.com/NixOS/nixpkgs/archive/217b3e910660fbf603b0995a6d2c3992aef4cc37.tar.gz"; # asof 10mar2024
|
||||
#inputs.nixpkgs.url = "https://github.com/NixOS/nixpkgs/archive/4dd376f7943c64b522224a548d9cab5627b4d9d6.tar.gz";
|
||||
|
||||
# inputs.nixpkgs.url
|
||||
# = "https://github.com/NixOS/nixpkgs/archive/fac3684647cc9d6dfb2a39f3f4b7cf5fc89c96b6.tar.gz"; # asof 8feb2024
|
||||
# fac3684647.. asof 17oct2023
|
||||
# instead of
|
||||
# inputs.nixpkgs.url = "github:nixos/nixpkgs/23.05";
|
||||
|
||||
inputs.flake-utils.url = "github:numtide/flake-utils";
|
||||
|
||||
# To add a new package, visit placeholder-A .. placeholder-E
|
||||
|
||||
inputs.xo-cmake-path = { type = "github"; owner = "Rconybea"; repo = "xo-cmake"; flake = false; };
|
||||
inputs.xo-indentlog-path = { type = "github"; owner = "Rconybea"; repo = "indentlog"; flake = false; };
|
||||
inputs.xo-flatstring-path = { type = "github"; owner = "Rconybea"; repo = "xo-flatstring"; flake = false; };
|
||||
inputs.xo-refcnt-path = { type = "github"; owner = "Rconybea"; repo = "refcnt"; flake = false; };
|
||||
inputs.xo-subsys-path = { type = "github"; owner = "Rconybea"; repo = "subsys"; flake = false; };
|
||||
inputs.xo-randomgen-path = { type = "github"; owner = "Rconybea"; repo = "randomgen"; flake = false; };
|
||||
inputs.xo-ratio-path = { type = "github"; owner = "Rconybea"; repo = "xo-ratio"; flake = false; };
|
||||
#inputs.xo-pyutil-path = { type = "github"; owner = "Rconybea"; repo = "xo-pyutil"; flake = false; };
|
||||
inputs.xo-reflect-path = { type = "github"; owner = "Rconybea"; repo = "reflect"; flake = false; };
|
||||
#inputs.xo-pyreflect-path = { type = "github"; owner = "Rconybea"; repo = "xo-pyreflect"; flake = false; };
|
||||
|
||||
# placeholder-A
|
||||
|
||||
outputs
|
||||
= { self,
|
||||
nixpkgs,
|
||||
flake-utils,
|
||||
xo-cmake-path,
|
||||
xo-indentlog-path,
|
||||
xo-flatstring-path,
|
||||
xo-refcnt-path,
|
||||
xo-subsys-path,
|
||||
xo-randomgen-path,
|
||||
xo-ratio-path,
|
||||
xo-reflect-path,
|
||||
# placeholder-B
|
||||
} :
|
||||
# out :: system -> {packages, devShells}
|
||||
let
|
||||
out
|
||||
= system :
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
|
||||
# could try using
|
||||
# appliedOverlay = (pkgs.extend self.overlays.default)
|
||||
# but it doesn't seem to work the way I expect,
|
||||
# For example, wants to pickup 2.7.11 python for xo-pyutil !
|
||||
#
|
||||
appliedOverlay = self.overlays.default pkgs pkgs;
|
||||
|
||||
in
|
||||
{
|
||||
#xo-cmake-dir = "${self.packages.${system}.xo-cmake}/share/cmake";
|
||||
|
||||
# reminder:
|
||||
# 'packages' comprises the output of this flake;
|
||||
# each defn invokes a build
|
||||
# ./pkgs/$example.nix
|
||||
# using
|
||||
# cmake-examples-$example-path
|
||||
# above for source code
|
||||
|
||||
packages.xo-cmake = appliedOverlay.xo-cmake;
|
||||
packages.xo-indentlog = appliedOverlay.xo-indentlog;
|
||||
packages.xo-flatstring = appliedOverlay.xo-flatstring;
|
||||
packages.xo-refcnt = appliedOverlay.xo-refcnt;
|
||||
packages.xo-subsys = appliedOverlay.xo-subsys;
|
||||
packages.xo-randomgen = appliedOverlay.xo-randomgen;
|
||||
packages.xo-ratio = appliedOverlay.xo-ratio;
|
||||
packages.xo-reflect = appliedOverlay.xo-reflect;
|
||||
packages.xo-unit = appliedOverlay.xo-unit;
|
||||
# placeholder-C
|
||||
|
||||
packages.xo-userenv = appliedOverlay.xo-userenv;
|
||||
|
||||
devShells = appliedOverlay.devShells;
|
||||
};
|
||||
in
|
||||
flake-utils.lib.eachDefaultSystem
|
||||
out
|
||||
//
|
||||
{
|
||||
# introduce overlay to extend nixpkgs with our local packages,
|
||||
# (which ofc are not present in nixpkgs, though same form would work if they were present)
|
||||
#
|
||||
overlays.default = final: prev:
|
||||
(
|
||||
let
|
||||
# can use
|
||||
# $ nix-env -qaP | grep \.boost # show known boost versions
|
||||
# $ nix-env -qaP | grep \.python.*Packages # show known python versions
|
||||
|
||||
stdenv = prev.stdenv;
|
||||
|
||||
boost = prev.boost182;
|
||||
python = prev.python311Full;
|
||||
pythonPackages = prev.python311Packages;
|
||||
#doxygen = prev.doxygen;
|
||||
|
||||
pybind11 = pythonPackages.pybind11;
|
||||
#breathe = pythonPackages.breathe;
|
||||
#sphinx = pythonPackages.sphinx;
|
||||
#sphinx-rtd-theme = pythonPackages.sphinx-rtd-theme;
|
||||
|
||||
#extras1 = { boost = boost; };
|
||||
#extras2 = { boost = boost; python3Packages = python3Packages; pybind11 = pybind11; };
|
||||
#extras3 = { boost = boost; python3Packages = python3Packages; pybind11 = pybind11; doxygen = doxygen; };
|
||||
#extras4 = extras3 // { breathe = breathe; };
|
||||
|
||||
xo-cmake =
|
||||
(prev.callPackage ./pkgs/xo-cmake.nix {}).overrideAttrs
|
||||
(old: { src = xo-cmake-path; });
|
||||
|
||||
xo-indentlog =
|
||||
(prev.callPackage ./pkgs/xo-indentlog.nix { xo-cmake = xo-cmake; }).overrideAttrs
|
||||
(old: { src = xo-indentlog-path; });
|
||||
|
||||
xo-flatstring =
|
||||
(prev.callPackage ./pkgs/xo-flatstring.nix { xo-cmake = xo-cmake;
|
||||
xo-indentlog = xo-indentlog;
|
||||
python = python;
|
||||
pythonPackages = pythonPackages; }).overrideAttrs
|
||||
(old: { src = xo-flatstring-path; });
|
||||
|
||||
xo-subsys =
|
||||
(prev.callPackage ./pkgs/xo-subsys.nix { xo-cmake = xo-cmake; }).overrideAttrs
|
||||
(old: { src = xo-subsys-path; });
|
||||
|
||||
xo-randomgen =
|
||||
(prev.callPackage ./pkgs/xo-randomgen.nix { xo-cmake = xo-cmake;
|
||||
xo-indentlog = xo-indentlog;
|
||||
}).overrideAttrs
|
||||
(old: { src = xo-randomgen-path; });
|
||||
|
||||
xo-ratio =
|
||||
(prev.callPackage ./pkgs/xo-ratio.nix { xo-cmake = xo-cmake;
|
||||
xo-flatstring = xo-flatstring;
|
||||
xo-randomgen = xo-randomgen;
|
||||
python = python;
|
||||
pythonPackages = pythonPackages;
|
||||
}).overrideAttrs
|
||||
(old: { src = xo-ratio-path; });
|
||||
|
||||
xo-refcnt =
|
||||
(prev.callPackage ./pkgs/xo-refcnt.nix { xo-cmake = xo-cmake;
|
||||
xo-indentlog = xo-indentlog; }).overrideAttrs
|
||||
(old: { src = xo-refcnt-path; });
|
||||
|
||||
xo-reflect =
|
||||
(prev.callPackage ./pkgs/xo-reflect.nix { xo-cmake = xo-cmake;
|
||||
xo-subsys = xo-subsys;
|
||||
xo-refcnt = xo-refcnt; }).overrideAttrs
|
||||
(old: { src = xo-reflect-path; });
|
||||
|
||||
xo-unit =
|
||||
(prev.callPackage ./pkgs/xo-unit.nix { xo-cmake = xo-cmake;
|
||||
xo-flatstring = xo-flatstring;
|
||||
xo-randomgen = xo-randomgen;
|
||||
xo-ratio = xo-ratio;
|
||||
python = python;
|
||||
pythonPackages = pythonPackages;
|
||||
}).overrideAttrs
|
||||
(old: { src = ./.; });
|
||||
|
||||
# placeholder-D
|
||||
|
||||
# user environment with all xo libraries present
|
||||
xo-userenv =
|
||||
(prev.callPackage ./pkgs/xo-userenv.nix { xo-cmake = xo-cmake;
|
||||
xo-indentlog = xo-indentlog;
|
||||
xo-flatstring = xo-flatstring;
|
||||
xo-subsys = xo-subsys;
|
||||
xo-refcnt = xo-refcnt;
|
||||
xo-randomgen = xo-randomgen;
|
||||
xo-ratio = xo-ratio;
|
||||
xo-reflect = xo-reflect;
|
||||
xo-unit = xo-unit;
|
||||
}).overrideAttrs(old: {});
|
||||
|
||||
|
||||
in
|
||||
# attrs in this set provide derivations with all overlay changes applied.
|
||||
#
|
||||
# REMINDER: need expression like
|
||||
# packages.xo-foo = appliedOverlay.xo-foo;
|
||||
# above to export
|
||||
{
|
||||
xo-cmake = xo-cmake;
|
||||
xo-indentlog = xo-indentlog;
|
||||
xo-flatstring = xo-flatstring;
|
||||
xo-subsys = xo-subsys;
|
||||
xo-refcnt = xo-refcnt;
|
||||
xo-randomgen = xo-randomgen;
|
||||
xo-ratio = xo-ratio;
|
||||
xo-reflect = xo-reflect;
|
||||
xo-unit = xo-unit;
|
||||
# placeholder-E
|
||||
|
||||
xo-userenv = xo-userenv;
|
||||
|
||||
devShells = {
|
||||
default = prev.mkShell.override
|
||||
# but may need prev.clang16Stdenv instead of prev.stdenv here on macos
|
||||
{ stdenv = prev.stdenv; }
|
||||
|
||||
{ packages
|
||||
= [ python
|
||||
pybind11
|
||||
pythonPackages.coverage
|
||||
pythonPackages.sphinx
|
||||
pythonPackages.sphinx-rtd-theme
|
||||
pythonPackages.breathe
|
||||
# pythonPackages.pyarrow
|
||||
boost # really for filemerge
|
||||
|
||||
prev.llvmPackages_16.clang-unwrapped
|
||||
|
||||
prev.anki
|
||||
prev.mesa
|
||||
prev.egl-wayland
|
||||
|
||||
prev.emacs29
|
||||
prev.notmuch
|
||||
prev.emacsPackages.notmuch
|
||||
prev.inconsolata-lgc
|
||||
|
||||
prev.doxygen
|
||||
prev.graphviz
|
||||
|
||||
prev.ditaa
|
||||
prev.semgrep
|
||||
prev.ripgrep
|
||||
prev.git
|
||||
prev.openssh
|
||||
prev.cmake
|
||||
prev.gdb
|
||||
prev.which
|
||||
prev.man
|
||||
prev.man-pages
|
||||
prev.less
|
||||
prev.tree
|
||||
prev.nix-tree
|
||||
prev.lcov
|
||||
|
||||
prev.arrow-cpp
|
||||
prev.libwebsockets
|
||||
prev.jsoncpp
|
||||
prev.eigen
|
||||
prev.catch2
|
||||
prev.pkg-config
|
||||
prev.zlib
|
||||
];
|
||||
};
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
}
|
||||
240
xo-unit/include/xo/unit/basis_unit.hpp
Normal file
240
xo-unit/include/xo/unit/basis_unit.hpp
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
/** @file basis_unit.hpp **/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "native_unit.hpp"
|
||||
#include "dimension.hpp"
|
||||
//#include "basis_unit_abbrev.hpp"
|
||||
#include "xo/ratio/ratio.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace qty {
|
||||
using bu_abbrev_type = flatstring<16>;
|
||||
using scalefactor_ratio_type = xo::ratio::ratio<std::int64_t>;
|
||||
using scalefactor2x_ratio_type = xo::ratio::ratio<__int128>;
|
||||
|
||||
/** @class basis_unit
|
||||
* @brief A dimensionless multiple of a single natively-specified basis dimension
|
||||
*
|
||||
* For example "3600 minutes" or "1e-6 grams".
|
||||
*
|
||||
* Members are public so that a @c basis_unit instance qualifies as a 'structural type',
|
||||
* and therefore may be used as a non-type template parameter.
|
||||
**/
|
||||
struct basis_unit {
|
||||
public:
|
||||
/** @defgroup basis-unit-constructors basis_unit constructors **/
|
||||
///@{
|
||||
/** sentinel basis unit: invalid dimension and zero scalefactor **/
|
||||
constexpr basis_unit() = default;
|
||||
/** basis unit representing multiple @p scalefactor of native dimension @p **/
|
||||
constexpr basis_unit(dimension native_dim,
|
||||
const scalefactor_ratio_type & scalefactor)
|
||||
: native_dim_{native_dim},
|
||||
scalefactor_{scalefactor}
|
||||
{}
|
||||
///@}
|
||||
|
||||
/** @defgroup basis-unit-access-methods basis_unit access methods **/
|
||||
///@{
|
||||
/** get @c native_dim member **/
|
||||
constexpr dimension native_dim() const { return native_dim_; }
|
||||
/** get @c scalefactor member **/
|
||||
constexpr const scalefactor_ratio_type & scalefactor() const { return scalefactor_; }
|
||||
///@}
|
||||
|
||||
public: /* public so instance can be a non-type template parameter (a structural type) */
|
||||
/** @defgroup basis-unit-instance-vars basis_unit instance variables **/
|
||||
///@{
|
||||
/** @brief identifies a native unit, e.g. time **/
|
||||
dimension native_dim_ = dimension::invalid;
|
||||
/** @brief this unit defined as multiple scalefactor times native unit **/
|
||||
scalefactor_ratio_type scalefactor_ = {};
|
||||
///@}
|
||||
};
|
||||
|
||||
/** @defgroup basis-unit-comparison-support basis_unit comparisons **/
|
||||
///@{
|
||||
/** @c true iff basis units are equal;
|
||||
* both native dimension and scalefactor must be equal
|
||||
**/
|
||||
inline constexpr bool
|
||||
operator==(const basis_unit & x, const basis_unit & y)
|
||||
{
|
||||
return ((x.native_dim_ == y.native_dim_)
|
||||
&& (x.scalefactor_ == y.scalefactor_));
|
||||
}
|
||||
|
||||
/** @c true iff bass units are not equal **/
|
||||
inline constexpr bool
|
||||
operator!=(const basis_unit & x, const basis_unit & y)
|
||||
{
|
||||
return ((x.native_dim_ != y.native_dim_)
|
||||
|| (x.scalefactor_ != y.scalefactor_));
|
||||
}
|
||||
///@}
|
||||
|
||||
namespace detail {
|
||||
/** @brief namespace for basis-unit constants and helpers **/
|
||||
namespace bu {
|
||||
// ----- mass -----
|
||||
|
||||
constexpr basis_unit mass_unit(std::int64_t num, std::int64_t den) {
|
||||
return basis_unit(dimension::mass, scalefactor_ratio_type(num, den));
|
||||
}
|
||||
|
||||
/** @defgroup basis-unit-mass-units basis_unit mass units **/
|
||||
///@{
|
||||
/** basis unit of 10^-12 grams **/
|
||||
constexpr basis_unit picogram = mass_unit( 1, 1000000000000);
|
||||
/** basis unit of 10^-9 grams **/
|
||||
constexpr basis_unit nanogram = mass_unit( 1, 1000000000);
|
||||
/** basis unit of 10^-6 grams **/
|
||||
constexpr basis_unit microgram = mass_unit( 1, 1000000);
|
||||
/** basis unit of 10^-3 grams **/
|
||||
constexpr basis_unit milligram = mass_unit( 1, 1000);
|
||||
/** basis unit of 1 gram **/
|
||||
constexpr basis_unit gram = mass_unit( 1, 1);
|
||||
/** basis unit of 10^3 grams **/
|
||||
constexpr basis_unit kilogram = mass_unit( 1000, 1);
|
||||
/** basis unit of 10^6 grams = 10^3 kilograms **/
|
||||
constexpr basis_unit tonne = mass_unit( 1000000, 1);
|
||||
/** basis unit of 10^9 grams = 10^6 kilograms = 10^3 tonnes **/
|
||||
constexpr basis_unit kilotonne = mass_unit( 1000000000, 1);
|
||||
/** basis unit of 10^12 grams = 10^9 kilograms = 10^6 tonnes **/
|
||||
constexpr basis_unit megatonne = mass_unit( 1000000000000, 1);
|
||||
/** basis unit of 10^15 grams = 10^12 kilograms = 10^9 tonnes **/
|
||||
constexpr basis_unit gigatonne = mass_unit(1000000000000000, 1);
|
||||
///@}
|
||||
|
||||
// ----- distance -----
|
||||
|
||||
constexpr basis_unit distance_unit(std::int64_t num, std::int64_t den) {
|
||||
return basis_unit(dimension::distance, scalefactor_ratio_type(num, den));
|
||||
}
|
||||
|
||||
/** @defgroup basis-unit-distance-units basis_unit distance units **/
|
||||
///@{
|
||||
/* US spelling */
|
||||
/** basis unit of 10^-12 meters **/
|
||||
constexpr basis_unit picometer = distance_unit( 1, 1000000000000);
|
||||
/** basis unit of 10^-9 meters **/
|
||||
constexpr basis_unit nanometer = distance_unit( 1, 1000000000);
|
||||
/** basis unit of 10^-6 meters **/
|
||||
constexpr basis_unit micrometer = distance_unit( 1, 1000000);
|
||||
/** basis unit of 10^-3 meters **/
|
||||
constexpr basis_unit millimeter = distance_unit( 1, 1000);
|
||||
/** basis unit of 1 meter **/
|
||||
constexpr basis_unit meter = distance_unit( 1, 1);
|
||||
/** basis unit of 10^3 meters **/
|
||||
constexpr basis_unit kilometer = distance_unit( 1000, 1);
|
||||
/** basis unit of 10^6 meters (for form's sake -- not commonly used) **/
|
||||
constexpr basis_unit megameter = distance_unit( 1000000, 1);
|
||||
/** basis unit of 10^9 meters (for form's sake -- not commonly used) **/
|
||||
constexpr basis_unit gigameter = distance_unit( 1000000000, 1);
|
||||
|
||||
/** basis unit of 1 light-second = distance light travels in a vacuum in 1 second **/
|
||||
constexpr basis_unit lightsecond = distance_unit( 299792458, 1);
|
||||
/** basis unit of 1 astronomical unit, representing approximate radius of earth orbit. **/
|
||||
constexpr basis_unit astronomicalunit = distance_unit( 149597870700, 1);
|
||||
|
||||
/* Int'l spelling */
|
||||
/** international spelling for picometer **/
|
||||
constexpr basis_unit picometre = picometer;
|
||||
/** international spelling for nanometer **/
|
||||
constexpr basis_unit nanometre = nanometer;
|
||||
/** international spelling for micrometer **/
|
||||
constexpr basis_unit micrometre = micrometer;
|
||||
/** international spelling for millimeter **/
|
||||
constexpr basis_unit millimetre = millimeter;
|
||||
/** international spelling for meter **/
|
||||
constexpr basis_unit metre = meter;
|
||||
/** international spelling for kilometer **/
|
||||
constexpr basis_unit kilometre = kilometer;
|
||||
/** international spelling for megameter **/
|
||||
constexpr basis_unit megametre = megameter;
|
||||
/** international spelling for gigameter **/
|
||||
constexpr basis_unit gigametre = gigameter;
|
||||
|
||||
/** @brief basis-unit representing 1 inch; defined as exactly 1/12 feet **/
|
||||
constexpr basis_unit inch = distance_unit( 3048, 120000);
|
||||
/** @brief basis-unit representing 1 foot; defined as exactly 0.3048 meters **/
|
||||
constexpr basis_unit foot = distance_unit( 3048, 10000);
|
||||
/** @brief basis-unit representing 1 yard; defined as exactly 3 feet **/
|
||||
constexpr basis_unit yard = distance_unit( 3*3048, 10000);
|
||||
/** @brief basis-unit representing 1 mile; defined as exactly 1760 yards = 5280 feet **/
|
||||
constexpr basis_unit mile = distance_unit( 5280*3048, 10000);
|
||||
///@}
|
||||
|
||||
// ----- time -----
|
||||
|
||||
constexpr basis_unit time_unit(std::int64_t num, std::int64_t den) {
|
||||
return basis_unit(dimension::time, scalefactor_ratio_type(num, den));
|
||||
}
|
||||
|
||||
/** @defgroup basis-unit-time-units basis_unit time units **/
|
||||
///@{
|
||||
/** basis unit of 10^-12 seconds **/
|
||||
constexpr basis_unit picosecond = time_unit( 1, 1000000000000);
|
||||
/** basis unit of 10^-9 seconds **/
|
||||
constexpr basis_unit nanosecond = time_unit( 1, 1000000000);
|
||||
/** basis unit of 10^-6 seconds **/
|
||||
constexpr basis_unit microsecond = time_unit( 1, 1000000);
|
||||
/** basis unit of 10^-3 seconds **/
|
||||
constexpr basis_unit millisecond = time_unit( 1, 1000);
|
||||
/** basis unit of 1 second **/
|
||||
constexpr basis_unit second = time_unit( 1, 1);
|
||||
/** basis unit of 1 minute = 60 seconds **/
|
||||
constexpr basis_unit minute = time_unit( 60, 1);
|
||||
/** basis unit of 1 hour = 3600 seconds **/
|
||||
constexpr basis_unit hour = time_unit( 3600, 1);
|
||||
/** basis unit of 1 day = exactly 24 hours **/
|
||||
constexpr basis_unit day = time_unit( 24*3600, 1);
|
||||
/** basis unit of 1 week = exactly 7 days **/
|
||||
constexpr basis_unit week = time_unit( 7*24*3600, 1);
|
||||
/** basis unit of 1 month = exactly 30 days **/
|
||||
constexpr basis_unit month = time_unit( 30*24*3600, 1);
|
||||
/** basis unit of 1 year, defined as 365.25 days **/
|
||||
constexpr basis_unit year = time_unit( (365*24+6)*3600, 1);
|
||||
|
||||
/* alt conventions used in finance */
|
||||
/** basis unit of 1 year365 = exactly 365 days **/
|
||||
constexpr basis_unit year365 = time_unit( 365*24*3600, 1);
|
||||
/** basis unit of 1 year360 = exactly 360 days **/
|
||||
constexpr basis_unit year360 = time_unit( 360*24*3600, 1);
|
||||
/** basis unit of 1 year250 = exactly 250 days.
|
||||
* Approximate number of business days in one year
|
||||
**/
|
||||
constexpr basis_unit year250 = time_unit( 250*24*3600, 1);
|
||||
|
||||
//constexpr basis_unit century = time_unit( 100L*(365*24+6)*3600, 1);
|
||||
//constexpr basis_unit millenium = time_unit(1000L*(365*24+6)*3600, 1);
|
||||
///@}
|
||||
|
||||
// ----- currency -----
|
||||
|
||||
/** @defgroup basis-unit-misc-units basis_unit miscellaneous units**/
|
||||
///@{
|
||||
|
||||
constexpr basis_unit currency_unit(std::int64_t num, std::int64_t den) {
|
||||
return basis_unit(dimension::currency, scalefactor_ratio_type(num, den));
|
||||
}
|
||||
|
||||
/** pseudounit -- placeholder for any actual currency amount **/
|
||||
constexpr basis_unit currency = currency_unit(1, 1);
|
||||
|
||||
// ----- price -----
|
||||
|
||||
constexpr basis_unit price_unit(std::int64_t num, std::int64_t den) {
|
||||
return basis_unit(dimension::price, scalefactor_ratio_type(num, den));
|
||||
}
|
||||
|
||||
/** psuedounit -- context-dependent interpretation for a screen price **/
|
||||
constexpr basis_unit price = price_unit(1, 1);
|
||||
///@}
|
||||
} /*namespace bu*/
|
||||
} /*namespace detail*/
|
||||
} /*namespace qty*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/** end basis_unit.hpp **/
|
||||
188
xo-unit/include/xo/unit/bpu.hpp
Normal file
188
xo-unit/include/xo/unit/bpu.hpp
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
/** @file bpu.hpp
|
||||
*
|
||||
* Author: Roland Conybeare
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "basis_unit.hpp"
|
||||
#include "bu_store.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace qty {
|
||||
namespace abbrev {
|
||||
/** fixed-size string representation for exponent of a basis-power-unit **/
|
||||
using power_abbrev_type = flatstring<16>;
|
||||
|
||||
/** @defgroup bpu-abbrev-helpers bpu abbrev helpers **/
|
||||
///@{
|
||||
/** @brief construct prefix string for unit exponent
|
||||
*
|
||||
* Auxiliary function for @ref bpu_abbrev
|
||||
**/
|
||||
constexpr power_abbrev_type
|
||||
flatstring_from_exponent(const power_ratio_type & power)
|
||||
{
|
||||
if (power.den() == 1) {
|
||||
if (power.num() == 1) {
|
||||
/* for no exponent annotation for power ^1 */
|
||||
return power_abbrev_type::from_chars("");
|
||||
} else {
|
||||
/* e.g. "^-1", "^2" */
|
||||
return (power_abbrev_type::from_flatstring
|
||||
(flatstring_concat(flatstring("^"),
|
||||
power_abbrev_type::from_int(power.num()))));
|
||||
}
|
||||
} else {
|
||||
/* e.g. "^1/2", "^-1/2" */
|
||||
return (power_abbrev_type::from_flatstring
|
||||
(flatstring_concat(flatstring("^"),
|
||||
power.to_str<power_abbrev_type::fixed_capacity>())));
|
||||
}
|
||||
}
|
||||
|
||||
/** construct suffix abbreviation for a basis-power-unit **/
|
||||
static constexpr bpu_abbrev_type
|
||||
bpu_abbrev(dim native_dim,
|
||||
const scalefactor_ratio_type & scalefactor,
|
||||
const power_ratio_type & power)
|
||||
{
|
||||
return (bpu_abbrev_type::from_flatstring
|
||||
(flatstring_concat
|
||||
(bu_abbrev(basis_unit(native_dim, scalefactor)),
|
||||
flatstring_from_exponent(power))));
|
||||
}
|
||||
///@}
|
||||
}
|
||||
|
||||
/** @class bpu
|
||||
*
|
||||
* @brief represent product of a compile-time scale-factor with a rational power of a native unit
|
||||
**/
|
||||
template<typename Int>
|
||||
struct bpu {
|
||||
public:
|
||||
using ratio_int_type = Int;
|
||||
|
||||
public:
|
||||
/** @defgroup bpu-ctors bpu constructors **/
|
||||
///@{
|
||||
/** default constructor. creates dimensionless bpu,
|
||||
* representing zero'th power of sentinel basis unit
|
||||
**/
|
||||
constexpr bpu() = default;
|
||||
/** construct @c bpu representing exponent @p power of basis unit @p bu **/
|
||||
constexpr bpu(const basis_unit & bu,
|
||||
const power_ratio_type & power)
|
||||
: bu_{bu},
|
||||
power_{power}
|
||||
{}
|
||||
/** construct @c bpu representing exponent @p power of @c basis_unit(native_dim,scalefactor) **/
|
||||
constexpr bpu(dim native_dim,
|
||||
const scalefactor_ratio_type & scalefactor,
|
||||
const power_ratio_type & power)
|
||||
: bu_(native_dim, scalefactor),
|
||||
power_{power}
|
||||
{}
|
||||
|
||||
/** construct bpu representing basis unit @p bu, i.e. with unit exponent **/
|
||||
static constexpr bpu<Int> unit_power(const basis_unit & bu) {
|
||||
return bpu<Int>(bu, power_ratio_type(1,1));
|
||||
}
|
||||
///@}
|
||||
|
||||
/** @defgroup bpu-access-methods bpu access methods **/
|
||||
///@{
|
||||
/** @brief report this bpu's @ref basis_unit, e.g. @c detail::bu::minute **/
|
||||
constexpr const basis_unit & bu() const { return bu_; }
|
||||
/** @brief report this bpu's @ref dimension, e.g. @c dimension::time **/
|
||||
constexpr dimension native_dim() const { return bu_.native_dim(); }
|
||||
/** @brief report this bpu's scale factor, e.g. @c 60/1 for @c detail::bu::minute **/
|
||||
constexpr const scalefactor_ratio_type & scalefactor() const { return bu_.scalefactor(); }
|
||||
/** @brief report this bpu's exponent, e.g. @c 3/1 for bpu representing cubic meters **/
|
||||
constexpr const power_ratio_type & power() const { return power_; }
|
||||
///@}
|
||||
|
||||
/** @defgroup bpu-methods **/
|
||||
///@{
|
||||
/** abbreviation for this dimension
|
||||
*
|
||||
* @code
|
||||
* bpu<int64_t>(dim::time,
|
||||
* scalefactor_ratio_type(60,1),
|
||||
* power_ratio_type(-2,1)).abbrev() => "min^-2"
|
||||
* @endcode
|
||||
**/
|
||||
constexpr bpu_abbrev_type abbrev() const
|
||||
{
|
||||
return abbrev::bpu_abbrev(bu_.native_dim_,
|
||||
bu_.scalefactor_,
|
||||
power_);
|
||||
}
|
||||
|
||||
/** for bpu @c x, @c x.reciprocal() represents dimension of @c 1/x
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* constexpr auto x = bpu<int64_t>(dim::time,
|
||||
* scalefactor_ratio_type(60,1),
|
||||
* power_ratio_type(1));
|
||||
* x.abbrev() => "min"
|
||||
* x.reciprocal().abbrev() => "min^-1"
|
||||
* @endcode
|
||||
**/
|
||||
constexpr bpu<Int> reciprocal() const {
|
||||
return bpu<Int>(bu_.native_dim(), bu_.scalefactor(), power_.negate());
|
||||
}
|
||||
|
||||
/** construct bpu representing the same unit, but using @c Int2 to represent exponenct **/
|
||||
template <typename Int2>
|
||||
constexpr bpu<Int2> to_repr() const {
|
||||
return bpu<Int2>(this->native_dim(),
|
||||
this->scalefactor(),
|
||||
ratio::ratio<Int2>(power_.num(), power_.den()));
|
||||
}
|
||||
///@}
|
||||
|
||||
public: /* need public members so that a basis_unit instance can be a non-type template parameter (a structural type) */
|
||||
/** @defgroup bpu-instance-vars **/
|
||||
///@{
|
||||
/** this @c bpu represent a power of basis unit @c bu.
|
||||
*
|
||||
* Public to avoid disqualifying @c bpu as a 'structural type'.
|
||||
**/
|
||||
struct basis_unit bu_;
|
||||
/** this unit represents basis dimension (bu) taken to this power
|
||||
*
|
||||
* Public to avoid disqualifying @c bpu as a 'structural type'.
|
||||
**/
|
||||
power_ratio_type power_ = {};
|
||||
///@}
|
||||
};
|
||||
|
||||
/** @defgroup bpu-comparison **/
|
||||
///@{
|
||||
/** @brief compare bpus @p x and @p y for equality
|
||||
*
|
||||
* Equality requires that both basis unit and power are equal
|
||||
**/
|
||||
template <typename Int>
|
||||
inline constexpr bool
|
||||
operator==(const bpu<Int> & x, const bpu<Int> & y) {
|
||||
return ((x.bu() == y.bu())
|
||||
&& (x.power_ == y.power_));
|
||||
}
|
||||
|
||||
/** @brief compare bpus @p x and @p y for inequality **/
|
||||
template <typename Int>
|
||||
inline constexpr bool
|
||||
operator!=(const bpu<Int> & x, const bpu<Int> & y) {
|
||||
return ((x.bu() != y.bu())
|
||||
|| (x.power_ != y.power_));
|
||||
}
|
||||
///@}
|
||||
|
||||
} /*namespace qty*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/** end bpu.hpp **/
|
||||
30
xo-unit/include/xo/unit/bpu_iostream.hpp
Normal file
30
xo-unit/include/xo/unit/bpu_iostream.hpp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/** @file bpu_iostream.hpp
|
||||
*
|
||||
* Author: Roland Conybeare
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "bpu.hpp"
|
||||
#include "dim_iostream.hpp"
|
||||
#include "xo/ratio/ratio_iostream.hpp"
|
||||
#include "xo/indentlog/print/tag.hpp"
|
||||
#include <iostream>
|
||||
|
||||
namespace xo {
|
||||
namespace qty {
|
||||
template <typename Int>
|
||||
inline std::ostream &
|
||||
operator<<(std::ostream & os, const bpu<Int> & x) {
|
||||
os << "<bpu"
|
||||
<< xtag("dim", x.native_dim())
|
||||
<< xtag("mult", x.scalefactor())
|
||||
<< xtag("pwr", x.power())
|
||||
<< ">";
|
||||
|
||||
return os;
|
||||
}
|
||||
} /*namespace qty*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/** end bpu_iostream.hpp **/
|
||||
279
xo-unit/include/xo/unit/bu_store.hpp
Normal file
279
xo-unit/include/xo/unit/bu_store.hpp
Normal file
|
|
@ -0,0 +1,279 @@
|
|||
/** @file bu_store.hpp **/
|
||||
|
||||
#pragma once
|
||||
|
||||
//#include "bpu.hpp"
|
||||
#include "basis_unit.hpp"
|
||||
#include "xo/ratio/ratio.hpp"
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
namespace xo {
|
||||
namespace qty {
|
||||
using bpu_abbrev_type = flatstring<24>;
|
||||
|
||||
using power_ratio_type = xo::ratio::ratio<std::int64_t>;
|
||||
|
||||
namespace detail {
|
||||
/** @class bu_dim_store
|
||||
* @brief store basis-unit abbreviations for a particular dimension
|
||||
**/
|
||||
struct bu_dim_store {
|
||||
/** max number of basis-units per dimension **/
|
||||
static constexpr std::size_t max_bu_per_dim = 25;
|
||||
|
||||
/** @defgroup bu-dim-store-type-traits bu-dim-store type traits **/
|
||||
///@{
|
||||
using entry_type = std::pair<scalefactor2x_ratio_type, bu_abbrev_type>;
|
||||
|
||||
/* e.g.
|
||||
* [(1/1000000000, "nm"), (1/1000000, "um"), (1/1000, "mm"), (1/1, "m"), (1000/1, "km")]
|
||||
*/
|
||||
using native_scale_v = std::array<entry_type, max_bu_per_dim>;
|
||||
///@}
|
||||
|
||||
public:
|
||||
constexpr bu_dim_store() = default;
|
||||
|
||||
constexpr bool empty() const { return n_bu_ == 0; }
|
||||
constexpr std::size_t size() const { return n_bu_; }
|
||||
|
||||
constexpr const entry_type & operator[](std::size_t i) const { return bu_abbrev_v_[i]; }
|
||||
|
||||
/** @brief get least-upper-bound index position in bu_abbrev_v[]
|
||||
*
|
||||
* return value in [0, n] where n = .size()
|
||||
**/
|
||||
constexpr std::size_t abbrev_lub_ix(const scalefactor_ratio_type & scalefactor) const
|
||||
{
|
||||
if (n_bu_ == 0)
|
||||
return 0;
|
||||
|
||||
std::size_t lo = 0;
|
||||
std::size_t hi = n_bu_-1;
|
||||
|
||||
if (scalefactor <= bu_abbrev_v_[lo].first)
|
||||
return 0;
|
||||
|
||||
auto cmp = (scalefactor <=> bu_abbrev_v_[hi].first);
|
||||
|
||||
if (cmp > 0)
|
||||
return n_bu_;
|
||||
|
||||
if (cmp == 0)
|
||||
return hi;
|
||||
|
||||
while (hi-lo > 1) {
|
||||
/* inv:
|
||||
* bu_abbrev_v[lo].first < scalefactor <= bu_abbrev_v[hi].first
|
||||
*/
|
||||
|
||||
std::size_t mid = lo + (hi - lo)/2;
|
||||
|
||||
if (scalefactor > bu_abbrev_v_[mid].first)
|
||||
lo = mid;
|
||||
else
|
||||
hi = mid;
|
||||
}
|
||||
|
||||
return hi;
|
||||
}
|
||||
|
||||
constexpr void insert_aux(std::size_t ix,
|
||||
const entry_type & entry)
|
||||
{
|
||||
|
||||
if (n_bu_ >= max_bu_per_dim)
|
||||
return;
|
||||
|
||||
++n_bu_;
|
||||
|
||||
for (std::size_t dest_ix = n_bu_; dest_ix > ix; --dest_ix)
|
||||
bu_abbrev_v_[dest_ix] = bu_abbrev_v_[dest_ix - 1];
|
||||
|
||||
bu_abbrev_v_[ix] = entry;
|
||||
}
|
||||
|
||||
/** @brief establish abbreviation @p abbrev for basis unit @p bu
|
||||
**/
|
||||
constexpr void bu_establish_abbrev(const scalefactor_ratio_type & scalefactor,
|
||||
const bu_abbrev_type & abbrev)
|
||||
{
|
||||
|
||||
std::int32_t i_abbrev = this->abbrev_lub_ix(scalefactor);
|
||||
|
||||
auto entry = std::make_pair(scalefactor, abbrev);
|
||||
|
||||
if ((i_abbrev < bu_abbrev_v_.size())
|
||||
&& (bu_abbrev_v_[i_abbrev].first == scalefactor))
|
||||
{
|
||||
bu_abbrev_v_[i_abbrev] = entry;
|
||||
} else {
|
||||
this->insert_aux(i_abbrev, entry);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/** @defgroup bu-dim-store-instance-vars bu-dim-store instance vars **/
|
||||
///@{
|
||||
std::size_t n_bu_ = 0;
|
||||
std::array<entry_type, max_bu_per_dim> bu_abbrev_v_;
|
||||
///@}
|
||||
}; /*bu_dim_store*/
|
||||
|
||||
/** @class bu_store
|
||||
* @brief associate basis units with abbreviations
|
||||
**/
|
||||
struct bu_store {
|
||||
/** @defgroup bu-store-constructors bu-store constructors **/
|
||||
///@{
|
||||
/** construct canonical instance containing all known basis units **/
|
||||
constexpr bu_store() {
|
||||
// ----- mass -----
|
||||
|
||||
this->bu_establish_abbrev(detail::bu::picogram, bu_abbrev_type::from_chars("pg"));
|
||||
this->bu_establish_abbrev(detail::bu::nanogram, bu_abbrev_type::from_chars("ng"));
|
||||
this->bu_establish_abbrev(detail::bu::microgram, bu_abbrev_type::from_chars("ug"));
|
||||
this->bu_establish_abbrev(detail::bu::milligram, bu_abbrev_type::from_chars("mg"));
|
||||
this->bu_establish_abbrev(detail::bu::gram, bu_abbrev_type::from_chars("g"));
|
||||
this->bu_establish_abbrev(detail::bu::kilogram, bu_abbrev_type::from_chars("kg"));
|
||||
this->bu_establish_abbrev(detail::bu::tonne, bu_abbrev_type::from_chars("t"));
|
||||
this->bu_establish_abbrev(detail::bu::kilotonne, bu_abbrev_type::from_chars("kt"));
|
||||
this->bu_establish_abbrev(detail::bu::megatonne, bu_abbrev_type::from_chars("Mt"));
|
||||
this->bu_establish_abbrev(detail::bu::gigatonne, bu_abbrev_type::from_chars("Gt"));
|
||||
|
||||
// ----- distance -----
|
||||
|
||||
this->bu_establish_abbrev(detail::bu::picometer, bu_abbrev_type::from_chars("pm"));
|
||||
this->bu_establish_abbrev(detail::bu::nanometer, bu_abbrev_type::from_chars("nm"));
|
||||
this->bu_establish_abbrev(detail::bu::micrometer, bu_abbrev_type::from_chars("um"));
|
||||
this->bu_establish_abbrev(detail::bu::millimeter, bu_abbrev_type::from_chars("mm"));
|
||||
this->bu_establish_abbrev(detail::bu::meter, bu_abbrev_type::from_chars("m"));
|
||||
this->bu_establish_abbrev(detail::bu::kilometer, bu_abbrev_type::from_chars("km"));
|
||||
this->bu_establish_abbrev(detail::bu::megameter, bu_abbrev_type::from_chars("Mm"));
|
||||
this->bu_establish_abbrev(detail::bu::gigameter, bu_abbrev_type::from_chars("Gm"));
|
||||
|
||||
this->bu_establish_abbrev(detail::bu::lightsecond, bu_abbrev_type::from_chars("lsec"));
|
||||
this->bu_establish_abbrev(detail::bu::astronomicalunit, bu_abbrev_type::from_chars("AU"));
|
||||
|
||||
this->bu_establish_abbrev(detail::bu::inch, bu_abbrev_type::from_chars("in"));
|
||||
this->bu_establish_abbrev(detail::bu::foot, bu_abbrev_type::from_chars("ft"));
|
||||
this->bu_establish_abbrev(detail::bu::yard, bu_abbrev_type::from_chars("yd"));
|
||||
this->bu_establish_abbrev(detail::bu::mile, bu_abbrev_type::from_chars("mi"));
|
||||
|
||||
// ----- time -----
|
||||
|
||||
this->bu_establish_abbrev(detail::bu::picosecond, bu_abbrev_type::from_chars("ps"));
|
||||
this->bu_establish_abbrev(detail::bu::nanosecond, bu_abbrev_type::from_chars("ns"));
|
||||
this->bu_establish_abbrev(detail::bu::microsecond, bu_abbrev_type::from_chars("us"));
|
||||
this->bu_establish_abbrev(detail::bu::millisecond, bu_abbrev_type::from_chars("ms"));
|
||||
this->bu_establish_abbrev(detail::bu::second, bu_abbrev_type::from_chars("s"));
|
||||
this->bu_establish_abbrev(detail::bu::minute, bu_abbrev_type::from_chars("min"));
|
||||
this->bu_establish_abbrev(detail::bu::hour, bu_abbrev_type::from_chars("hr"));
|
||||
this->bu_establish_abbrev(detail::bu::day, bu_abbrev_type::from_chars("dy"));
|
||||
this->bu_establish_abbrev(detail::bu::week, bu_abbrev_type::from_chars("wk"));
|
||||
this->bu_establish_abbrev(detail::bu::month, bu_abbrev_type::from_chars("mo"));
|
||||
this->bu_establish_abbrev(detail::bu::year250, bu_abbrev_type::from_chars("yr250"));
|
||||
this->bu_establish_abbrev(detail::bu::year, bu_abbrev_type::from_chars("yr"));
|
||||
this->bu_establish_abbrev(detail::bu::year360, bu_abbrev_type::from_chars("yr360"));
|
||||
this->bu_establish_abbrev(detail::bu::year365, bu_abbrev_type::from_chars("yr365"));
|
||||
|
||||
// ----- misc (currency, price) -----
|
||||
|
||||
this->bu_establish_abbrev(detail::bu::currency, bu_abbrev_type::from_chars("ccy"));
|
||||
this->bu_establish_abbrev(detail::bu::price, bu_abbrev_type::from_chars("px"));
|
||||
}
|
||||
///@}
|
||||
|
||||
/** @defgroup bu-store-implementation-methods **/
|
||||
///@{
|
||||
/** report fallback abbreviation for a basis unit.
|
||||
*
|
||||
* Typically unused. Will be invoked only if a basis unit exists for which
|
||||
* @ref bu_store::bu_establish_abbrev was not called by bu_store's constructor.
|
||||
*
|
||||
* Tries to produce something unambiguous,
|
||||
* while still supplying enough information
|
||||
* to indicate what's needed to resolve the problem.
|
||||
*
|
||||
* Example
|
||||
* @code
|
||||
* bu_store.bu_fallback_abbrev(dim::mass, scalefactor_ratio_type(1234,1))
|
||||
* => "1234g"
|
||||
* @endcode
|
||||
**/
|
||||
static constexpr bu_abbrev_type
|
||||
bu_fallback_abbrev(dim basis_dim,
|
||||
const scalefactor_ratio_type & scalefactor)
|
||||
{
|
||||
return (bu_abbrev_type::from_flatstring
|
||||
(flatstring_concat
|
||||
(scalefactor.to_str<bu_abbrev_type::fixed_capacity>(),
|
||||
native_unit2_v[static_cast<std::uint32_t>(basis_dim)].abbrev_str())));
|
||||
}
|
||||
///@}
|
||||
|
||||
/** @defgroup bu-store-access-methods **/
|
||||
///@{
|
||||
/** @brief get basis-unit abbreviation at runtime **/
|
||||
constexpr bu_abbrev_type bu_abbrev(const basis_unit & bu) const
|
||||
{
|
||||
const auto & bu_abbrev_v = bu_abbrev_vv_[static_cast<std::size_t>(bu.native_dim())];
|
||||
|
||||
std::size_t i_abbrev = bu_abbrev_v.abbrev_lub_ix(bu.scalefactor());
|
||||
|
||||
if ((i_abbrev < bu_abbrev_v.size())
|
||||
&& (bu_abbrev_v[i_abbrev].first == bu.scalefactor()))
|
||||
{
|
||||
return bu_abbrev_v[i_abbrev].second;
|
||||
} else {
|
||||
return bu_fallback_abbrev(bu.native_dim(), bu.scalefactor());
|
||||
}
|
||||
}
|
||||
///@}
|
||||
|
||||
/** @addtogroup bu-store-implementation-methods **/
|
||||
///@{
|
||||
/** associate abbreviation @p abbrev with basis unit @p bu
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* // femtograms
|
||||
* bu_store.bu_establish_abbrev(detail::bu::mass_unit(1, 1000000000000000), "fg")
|
||||
* @endcode
|
||||
**/
|
||||
constexpr void bu_establish_abbrev(const basis_unit & bu,
|
||||
const bu_abbrev_type & abbrev) {
|
||||
auto & dim_store = bu_abbrev_vv_[static_cast<std::size_t>(bu.native_dim_)];
|
||||
|
||||
dim_store.bu_establish_abbrev(bu.scalefactor_, abbrev);
|
||||
}
|
||||
///@}
|
||||
|
||||
public: /* ntoe: public members required so bu_dim_store can be a structural type */
|
||||
/** @defgroup bu-store-instance-vars **/
|
||||
///@{
|
||||
/** bu-store contents, indexed by native dimension **/
|
||||
std::array<bu_dim_store, n_dim> bu_abbrev_vv_;
|
||||
///@}
|
||||
};
|
||||
} /*namespace detail*/
|
||||
|
||||
/** @brief global abbreviation store.
|
||||
*
|
||||
* @note
|
||||
* Extending the contents of this store at runtime is not supported,
|
||||
* in favor of preserving constexpr abbreviations.
|
||||
**/
|
||||
static constexpr detail::bu_store bu_abbrev_store;
|
||||
|
||||
/** @brief get abbreviation for basis-unit @p bu **/
|
||||
constexpr bu_abbrev_type
|
||||
bu_abbrev(const basis_unit & bu)
|
||||
{
|
||||
return bu_abbrev_store.bu_abbrev(bu);
|
||||
}
|
||||
} /*namespace qty*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/** end bu_store.hpp **/
|
||||
21
xo-unit/include/xo/unit/dim_iostream.hpp
Normal file
21
xo-unit/include/xo/unit/dim_iostream.hpp
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/** @file dim_iostream.hpp
|
||||
*
|
||||
* Author: Roland Conybeare
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "dimension.hpp"
|
||||
#include <iostream>
|
||||
|
||||
namespace xo {
|
||||
namespace qty {
|
||||
inline std::ostream &
|
||||
operator<<(std::ostream & os, dim x) {
|
||||
os << dim2str(x);
|
||||
return os;
|
||||
}
|
||||
} /*namespace qty*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/** end dim_iostream.hpp **/
|
||||
65
xo-unit/include/xo/unit/dimension.hpp
Normal file
65
xo-unit/include/xo/unit/dimension.hpp
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/* @file dimension.hpp */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace xo {
|
||||
namespace qty {
|
||||
/** @enum dimension
|
||||
* @brief represent an abstract dimension.
|
||||
*
|
||||
* *xo-unit* units are expressed as a cartesian product
|
||||
* of powers of these dimensions.
|
||||
**/
|
||||
enum class dimension {
|
||||
/** sentinel value. not a dimension **/
|
||||
invalid = -1,
|
||||
|
||||
/** weight. native unit = 1 gram **/
|
||||
mass,
|
||||
/** distance. native unit = 1 meter **/
|
||||
distance,
|
||||
/** time. native unit = 1 second **/
|
||||
time,
|
||||
/** a currency amount. native unit depends on actual currency.
|
||||
* For USD: one US dollar.
|
||||
*
|
||||
* NOTE: multicurrency work not supported by *xo-unit*.
|
||||
* - (1usd + 1eur) is well-defined.
|
||||
* - (1sec + 1m) is not.
|
||||
**/
|
||||
currency,
|
||||
/** A screen price.
|
||||
* The interpretation of prices is highly context dependent;
|
||||
* expect useful to bucket separately from currenty amounts.
|
||||
**/
|
||||
price,
|
||||
|
||||
/** not a dimension. comes last, counts entries **/
|
||||
n_dim
|
||||
};
|
||||
|
||||
using dim = dimension;
|
||||
|
||||
/** @brief string value for a dimension enum **/
|
||||
inline const char *
|
||||
dim2str(dimension x)
|
||||
{
|
||||
switch(x) {
|
||||
case dimension::mass: return "mass";
|
||||
case dimension::distance: return "distance";
|
||||
case dimension::time: return "time";
|
||||
case dimension::currency: return "currency";
|
||||
case dimension::price: return "price";
|
||||
default: break;
|
||||
}
|
||||
return "?dim";
|
||||
}
|
||||
|
||||
/** @brief number of built-in dimensions, convenient for array sizing **/
|
||||
static constexpr std::size_t n_dim = static_cast<std::size_t>(dimension::n_dim);
|
||||
} /*namespace qty*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end dimension.hpp */
|
||||
49
xo-unit/include/xo/unit/native_unit.hpp
Normal file
49
xo-unit/include/xo/unit/native_unit.hpp
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/** @file native_unit.hpp
|
||||
*
|
||||
* Author: Roland Conybeare
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "dimension.hpp"
|
||||
#include "xo/flatstring/flatstring.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace qty {
|
||||
using native_unit2_abbrev_type = flatstring<8>;
|
||||
|
||||
/** @class native_unit
|
||||
*
|
||||
* @brief Represent a native (built-in) unit.
|
||||
*
|
||||
* A basis_unit is expressed as a multiple of a native_unit
|
||||
*
|
||||
**/
|
||||
struct native_unit {
|
||||
public:
|
||||
constexpr native_unit(dimension native_dim,
|
||||
const native_unit2_abbrev_type & abbrev_str)
|
||||
: native_dim_{native_dim},
|
||||
abbrev_str_{abbrev_str}
|
||||
{}
|
||||
|
||||
constexpr dimension native_dim() const { return native_dim_; }
|
||||
constexpr const native_unit2_abbrev_type & abbrev_str() const { return abbrev_str_; }
|
||||
|
||||
private:
|
||||
dimension native_dim_;
|
||||
native_unit2_abbrev_type abbrev_str_;
|
||||
};
|
||||
|
||||
static constexpr native_unit native_unit2_v[n_dim] = {
|
||||
native_unit(dimension::mass, native_unit2_abbrev_type::from_chars("g")),
|
||||
native_unit(dimension::distance, native_unit2_abbrev_type::from_chars("m")),
|
||||
native_unit(dimension::time, native_unit2_abbrev_type::from_chars("s")),
|
||||
native_unit(dimension::currency, native_unit2_abbrev_type::from_chars("ccy")),
|
||||
native_unit(dimension::price, native_unit2_abbrev_type::from_chars("px")),
|
||||
};
|
||||
|
||||
} /*namespace qty*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/** end native_unit.hpp **/
|
||||
527
xo-unit/include/xo/unit/natural_unit.hpp
Normal file
527
xo-unit/include/xo/unit/natural_unit.hpp
Normal file
|
|
@ -0,0 +1,527 @@
|
|||
/** @file natural_unit.hpp
|
||||
*
|
||||
* Author: Roland Conybeare
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "bpu.hpp"
|
||||
#include <cmath>
|
||||
#include <cassert>
|
||||
|
||||
namespace xo {
|
||||
namespace qty {
|
||||
using nu_abbrev_type = flatstring<32>;
|
||||
|
||||
template <typename Int>
|
||||
class natural_unit;
|
||||
|
||||
namespace detail {
|
||||
template <typename Int, typename... Ts>
|
||||
constexpr void
|
||||
push_bpu_array(natural_unit<Int> * p_target, Ts... args);
|
||||
|
||||
template <typename Int>
|
||||
constexpr void
|
||||
push_bpu_array(natural_unit<Int> * p_target) {}
|
||||
|
||||
template <typename Int, typename T0, typename... Ts>
|
||||
constexpr void
|
||||
push_bpu_array(natural_unit<Int> * p_target, T0 && bpu0, Ts... args) {
|
||||
p_target->push_back(bpu0);
|
||||
push_bpu_array(p_target, args...);
|
||||
}
|
||||
|
||||
template <typename Int>
|
||||
struct nu_maker {
|
||||
template <typename... Ts>
|
||||
static constexpr natural_unit<Int>
|
||||
make_nu(Ts... args) {
|
||||
natural_unit<Int> bpu_array;
|
||||
detail::push_bpu_array(&bpu_array, args...);
|
||||
return bpu_array;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** @class natural_unit
|
||||
* @brief an array representing the cartesian product of distinct basis-power-units
|
||||
*
|
||||
* 1. Quantities are represented as a multiple of a natural unit
|
||||
* 2. Each bpu in the array represents a power of a basis dimension, e.g. "meter" or "second^2".
|
||||
* 3. Each bpu in an array has a different dimension id.
|
||||
* For example @c dim::time, if present, appears once.
|
||||
* 4. Basis dimensions can appear in any order.
|
||||
* Order used for constructing abbreviations: will get @c "kg.m" or @c "m.kg"
|
||||
* depending on the ordering of @c dim::distance and @c dim::mass in @c bpu_v_
|
||||
*
|
||||
* @c Int supplies representation for numerator and denominator in basis-unit scale factors.
|
||||
**/
|
||||
template <typename Int>
|
||||
class natural_unit {
|
||||
public:
|
||||
/** @defgroup natural-unit-type-traits natural unit type traits **/
|
||||
///@{
|
||||
/** @brief representation for numerator and denominator of scalefactor ratios **/
|
||||
using ratio_int_type = Int;
|
||||
///@}
|
||||
|
||||
public:
|
||||
/** @addtogroup natural-unit-ctors **/
|
||||
///@{
|
||||
|
||||
/** construct dimensionless unit **/
|
||||
constexpr natural_unit() : n_bpu_{0} {}
|
||||
|
||||
/** construct unit representing basis unit @p bu with exponent @p power **/
|
||||
static constexpr natural_unit from_bu(basis_unit bu,
|
||||
power_ratio_type power = power_ratio_type(1)) {
|
||||
return detail::nu_maker<Int>::make_nu(bpu<Int>(bu, power));
|
||||
}
|
||||
|
||||
///@}
|
||||
|
||||
/** @addtogroup natural-unit-access-methods **/
|
||||
///@{
|
||||
|
||||
/** always true. Provided for symmetry with @c xo::qty::scaled_unit::is_natural **/
|
||||
constexpr bool is_natural() const { return true; }
|
||||
|
||||
/** get member @c n_bpu **/
|
||||
constexpr std::size_t n_bpu() const { return n_bpu_; }
|
||||
/** true if this unit has no dimension **/
|
||||
constexpr bool is_dimensionless() const { return n_bpu_ == 0; }
|
||||
|
||||
/** get address of member @c bpu_v **/
|
||||
constexpr bpu<Int> * bpu_v() const { return bpu_v_; }
|
||||
|
||||
///@}
|
||||
|
||||
/** @defgroup natural-unit-methods **/
|
||||
///@{
|
||||
|
||||
/** construct reciprocal of this unit.
|
||||
*
|
||||
* For example reciprocal of a newton (abbreviation @c "kg.m.s^-2") is
|
||||
* a unit with abbreviation @c "kg^-1.m^-1.s^2"
|
||||
**/
|
||||
constexpr natural_unit reciprocal() const {
|
||||
natural_unit retval;
|
||||
|
||||
for (std::size_t i = 0; i < this->n_bpu(); ++i)
|
||||
retval.push_back((*this)[i].reciprocal());
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/** abbreviation for this unit.
|
||||
*
|
||||
* Apply as suffix when printing quantities involving this unit.
|
||||
*
|
||||
* For example @c "mm" for millimeters, or @c "ns" for nanoseconds
|
||||
**/
|
||||
constexpr nu_abbrev_type abbrev() const {
|
||||
nu_abbrev_type retval;
|
||||
|
||||
for (std::size_t i = 0; i < n_bpu_; ++i) {
|
||||
if (i > 0)
|
||||
retval.append(".");
|
||||
retval.append(bpu_v_[i].abbrev(), 0, -1);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/** remove bpu at position @p p **/
|
||||
constexpr void remove_bpu(size_t p) {
|
||||
for (std::size_t i = p; i+1 < n_bpu_; ++i)
|
||||
bpu_v_[i] = bpu_v_[i+1];
|
||||
|
||||
--n_bpu_;
|
||||
}
|
||||
|
||||
/** append @p bpu to this unit in-place
|
||||
*
|
||||
* Require @c bpu.native_dim does not match any existing member of @ref bpu_v_
|
||||
**/
|
||||
constexpr void push_back(const bpu<Int> & bpu) {
|
||||
if (n_bpu_ < n_dim)
|
||||
bpu_v_[n_bpu_++] = bpu;
|
||||
}
|
||||
|
||||
///@}
|
||||
|
||||
/** @addtogroup natural-unit-access-methods **/
|
||||
///@{
|
||||
|
||||
/** get bpu for dimension @p d. if d isn't present, construct bpu with 0 power **/
|
||||
constexpr bpu<Int> lookup_dim(dimension d) const {
|
||||
for (std::size_t i = 0, n = n_bpu(); i<n; ++i) {
|
||||
if (d == bpu_v_[i].native_dim())
|
||||
return bpu_v_[i];
|
||||
}
|
||||
|
||||
/** not found, return sentinel **/
|
||||
return bpu<Int>(d, scalefactor_ratio_type(0), power_ratio_type(0));
|
||||
}
|
||||
|
||||
/** get element @p i of @ref bpu_v_ **/
|
||||
constexpr bpu<Int> & operator[](std::size_t i) { return bpu_v_[i]; }
|
||||
/** get element @p i of @ref bpu_v_ (const version) **/
|
||||
constexpr const bpu<Int> & operator[](std::size_t i) const { return bpu_v_[i]; }
|
||||
|
||||
///@}
|
||||
|
||||
/** @defgroup natural-unit-conversion-methods **/
|
||||
///@{
|
||||
|
||||
/** convert to equivalent unit using scalefactor representation @p Int2 instead of
|
||||
* @ref ratio_int_type
|
||||
**/
|
||||
template <typename Int2>
|
||||
constexpr natural_unit<Int2> to_repr() const {
|
||||
natural_unit<Int2> retval;
|
||||
|
||||
std::size_t i = 0;
|
||||
for (; i < n_bpu_; ++i)
|
||||
retval.push_back(bpu_v_[i].template to_repr<Int2>());
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
///@}
|
||||
|
||||
public: /* public members so instance can be non-type template parameter (is a structural type) */
|
||||
/** @defgroup natural-unit-instance-vars **/
|
||||
///@{
|
||||
|
||||
/** the number of occupied slots in @c bpu_v_ **/
|
||||
std::size_t n_bpu_;
|
||||
|
||||
/** storage for basis power units **/
|
||||
bpu<Int> bpu_v_[n_dim];
|
||||
|
||||
///@}
|
||||
};
|
||||
|
||||
/** @defgroup natural-unit-comparison-functions natural-unit comparison functions **/
|
||||
///@{
|
||||
|
||||
/** compare natural units @p x, @p y for equality. **/
|
||||
template <typename Int>
|
||||
constexpr bool
|
||||
operator==(const natural_unit<Int> & x,
|
||||
const natural_unit<Int> & y)
|
||||
{
|
||||
if (x.n_bpu() != y.n_bpu())
|
||||
return false;
|
||||
|
||||
/* does x contain any dimension that isn't present in y? */
|
||||
for (std::size_t i = 0, n = x.n_bpu(); i<n; ++i) {
|
||||
const bpu<Int> & xi = x[i];
|
||||
if (xi != y.lookup_dim(xi.native_dim()))
|
||||
return false;
|
||||
}
|
||||
|
||||
/* if all bpu's x[i] match something from y, then x,y must be equal
|
||||
* since they each have the same number of bpu's
|
||||
*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** compare natural units @p x, @p y for inequality **/
|
||||
template <typename Int>
|
||||
constexpr bool
|
||||
operator!=(const natural_unit<Int> & x,
|
||||
const natural_unit<Int> & y) {
|
||||
return !(x == y);
|
||||
}
|
||||
|
||||
///@}
|
||||
|
||||
namespace detail {
|
||||
/**
|
||||
* Given bpu ~ (b.u)^p:
|
||||
* - b = bpu.scalefactor
|
||||
* - u = bpu.native_dim
|
||||
* - p = bpu.power
|
||||
*
|
||||
* want to rewrite in the form a'.(b'.u)^p
|
||||
*
|
||||
* Can compute a' exactly iff p is integral.
|
||||
* In that case:
|
||||
* (b.u)^p = ((b/b').b'.u)^p
|
||||
* = (b/b')^p.(b'.u)^p
|
||||
* = a'.(b'.u)^p with a' = (b/b')^p
|
||||
*
|
||||
* Can write p = p0 + q, with p0 = floor(p) integral, q = frac(p) in [0,1)
|
||||
*
|
||||
* Then
|
||||
* (b/b')^p = (b/b')^p0 * (b/b')^q
|
||||
*
|
||||
* we'll compute:
|
||||
* - (b/b')^p0 exactly (as a ratio)
|
||||
* - (b/b')^q inexactly (as a double)
|
||||
**/
|
||||
|
||||
template <typename Int,
|
||||
typename OuterScale = ratio::ratio<Int> >
|
||||
struct outer_scalefactor_result {
|
||||
constexpr outer_scalefactor_result(const OuterScale & outer_scale_factor,
|
||||
double outer_scale_sq)
|
||||
: outer_scale_factor_{outer_scale_factor},
|
||||
outer_scale_sq_{outer_scale_sq} {}
|
||||
|
||||
/* (b/b')^p0 */
|
||||
OuterScale outer_scale_factor_;
|
||||
/* (b/b')^q -- until c++26 only allow q=0 or q=1/2 */
|
||||
double outer_scale_sq_;
|
||||
};
|
||||
|
||||
template <typename Int,
|
||||
typename OuterScale = ratio::ratio<Int> >
|
||||
struct bpu2_rescale_result {
|
||||
constexpr bpu2_rescale_result(const bpu<Int> & bpu_rescaled,
|
||||
const OuterScale & outer_scale_factor,
|
||||
double outer_scale_sq)
|
||||
: bpu_rescaled_{bpu_rescaled},
|
||||
outer_scale_factor_{outer_scale_factor},
|
||||
outer_scale_sq_{outer_scale_sq}
|
||||
{}
|
||||
|
||||
/* (b'.u)^p */
|
||||
bpu<Int> bpu_rescaled_;
|
||||
/* (b/b')^p0 */
|
||||
OuterScale outer_scale_factor_;
|
||||
/* [(b/b')^q]^2 -- until c++26 only allow q=0 or q=1/2 */
|
||||
double outer_scale_sq_;
|
||||
};
|
||||
|
||||
template < typename Int,
|
||||
typename OuterScale = ratio::ratio<Int> >
|
||||
constexpr
|
||||
bpu2_rescale_result<Int, OuterScale>
|
||||
bpu2_rescale(const bpu<Int> & orig,
|
||||
const scalefactor_ratio_type & new_scalefactor)
|
||||
{
|
||||
/* we have orig, representing qty (b.u)^p,
|
||||
* with b=orig.scalefactor, u=native dimension, p=orig.power
|
||||
*/
|
||||
|
||||
ratio::ratio<Int> mult = (orig.scalefactor() / new_scalefactor);
|
||||
|
||||
/* inv: p_frac in (-1, 1) */
|
||||
auto p_frac = orig.power().frac();
|
||||
|
||||
/* asof c++26: replace mult_sq with ::pow(mult, p_frac) */
|
||||
double mult_sq = std::numeric_limits<double>::quiet_NaN();
|
||||
|
||||
/* pre-c++26 workaround */
|
||||
{
|
||||
if (p_frac.den() == 1) {
|
||||
mult_sq = 1.0;
|
||||
} else if(p_frac.num() == 1 && p_frac.den() == 2) {
|
||||
mult_sq = mult.template convert_to<double>();
|
||||
} else if(p_frac.num() == -1 && p_frac.den() == 2) {
|
||||
mult_sq = 1.0 / mult.template convert_to<double>();
|
||||
} else {
|
||||
// remaining possibilities not supported until c++26
|
||||
}
|
||||
}
|
||||
|
||||
ratio::ratio<Int> mult_p = mult.power(orig.power().floor());
|
||||
|
||||
return bpu2_rescale_result<Int, OuterScale>(bpu<Int>(orig.native_dim(),
|
||||
new_scalefactor,
|
||||
orig.power()),
|
||||
mult_p.template convert_to<OuterScale>(),
|
||||
mult_sq);
|
||||
}
|
||||
|
||||
template < typename Int,
|
||||
typename OuterScale >
|
||||
constexpr
|
||||
outer_scalefactor_result<Int, OuterScale>
|
||||
bpu_product_inplace(bpu<Int> * p_target_bpu,
|
||||
const bpu<Int> & rhs_bpu_orig)
|
||||
{
|
||||
assert(rhs_bpu_orig.native_dim() == p_target_bpu->native_dim());
|
||||
|
||||
bpu2_rescale_result<Int, OuterScale> rhs_bpu_rr
|
||||
= bpu2_rescale<Int, OuterScale>(rhs_bpu_orig,
|
||||
p_target_bpu->scalefactor().template convert_to<OuterScale>());
|
||||
|
||||
*p_target_bpu = bpu<Int>(p_target_bpu->native_dim(),
|
||||
p_target_bpu->scalefactor(),
|
||||
p_target_bpu->power() + rhs_bpu_orig.power());
|
||||
|
||||
return outer_scalefactor_result<Int>(rhs_bpu_rr.outer_scale_factor_,
|
||||
rhs_bpu_rr.outer_scale_sq_);
|
||||
}
|
||||
|
||||
template < typename Int,
|
||||
typename OuterScale >
|
||||
constexpr
|
||||
outer_scalefactor_result<Int, OuterScale>
|
||||
bpu_ratio_inplace(bpu<Int> * p_target_bpu,
|
||||
const bpu<Int> & rhs_bpu_orig)
|
||||
{
|
||||
assert(rhs_bpu_orig.native_dim() == p_target_bpu->native_dim());
|
||||
|
||||
bpu2_rescale_result<Int, OuterScale> rhs_bpu_rr
|
||||
= bpu2_rescale<Int, OuterScale>(rhs_bpu_orig,
|
||||
p_target_bpu->scalefactor());
|
||||
|
||||
*p_target_bpu = bpu<Int>(p_target_bpu->native_dim(),
|
||||
p_target_bpu->scalefactor(),
|
||||
p_target_bpu->power() - rhs_bpu_orig.power());
|
||||
|
||||
return outer_scalefactor_result<Int, OuterScale>
|
||||
(OuterScale(1) / rhs_bpu_rr.outer_scale_factor_,
|
||||
1.0 / rhs_bpu_rr.outer_scale_sq_);
|
||||
}
|
||||
|
||||
template < typename Int,
|
||||
typename OuterScale >
|
||||
constexpr
|
||||
outer_scalefactor_result<Int, OuterScale>
|
||||
nu_product_inplace(natural_unit<Int> * p_target,
|
||||
const bpu<Int> & bpu)
|
||||
{
|
||||
std::size_t i = 0;
|
||||
for (; i < p_target->n_bpu(); ++i) {
|
||||
auto * p_target_bpu = &((*p_target)[i]);
|
||||
|
||||
if (p_target_bpu->native_dim() == bpu.native_dim()) {
|
||||
outer_scalefactor_result<Int, OuterScale> retval
|
||||
= bpu_product_inplace<Int, OuterScale>(p_target_bpu, bpu);
|
||||
|
||||
if (p_target_bpu->power().is_zero()) {
|
||||
/* dimension assoc'd with *p_target_bpu has been cancelled */
|
||||
p_target->remove_bpu(i);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
/* control here: i=p_target->n_bpu()
|
||||
* Dimension represented by bpu does not already appear in *p_target.
|
||||
* Adopt bpu's scalefactor
|
||||
*/
|
||||
|
||||
p_target->push_back(bpu);
|
||||
|
||||
return outer_scalefactor_result<Int, OuterScale>
|
||||
(OuterScale(1) /*outer_scale_factor*/,
|
||||
1.0 /*outer_scale_sq*/);
|
||||
}
|
||||
|
||||
template < typename Int,
|
||||
typename OuterScale = ratio::ratio<Int> >
|
||||
constexpr
|
||||
outer_scalefactor_result<Int, OuterScale>
|
||||
nu_ratio_inplace(natural_unit<Int> * p_target,
|
||||
const bpu<Int> & bpu)
|
||||
{
|
||||
std::size_t i = 0;
|
||||
for (; i < p_target->n_bpu(); ++i) {
|
||||
auto * p_target_bpu = &((*p_target)[i]);
|
||||
|
||||
if (p_target_bpu->native_dim() == bpu.native_dim()) {
|
||||
outer_scalefactor_result<Int, OuterScale> retval
|
||||
= bpu_ratio_inplace<Int, OuterScale>(p_target_bpu, bpu);
|
||||
|
||||
if (p_target_bpu->power().is_zero()) {
|
||||
/* dimension assoc'd with *p_target_bpu has been cancelled */
|
||||
p_target->remove_bpu(i);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
/* here: i=p_target->n_bpu()
|
||||
* Dimension represented by bpu does not already appear in *p_target.
|
||||
* Adopt bpu's scalefactor
|
||||
*/
|
||||
|
||||
p_target->push_back(bpu.reciprocal());
|
||||
|
||||
return outer_scalefactor_result<Int, OuterScale>
|
||||
(OuterScale(1) /*outer_scale_factor*/,
|
||||
1.0 /*outer_scale_sq*/);
|
||||
}
|
||||
|
||||
} /*namespace detail*/
|
||||
|
||||
/** @brief namespace for constants representing basis natural units
|
||||
*
|
||||
* Application code will typically use instead parallel scaled-unit constants
|
||||
* (see the 'u' namespace in 'scaled_unit.hpp')
|
||||
**/
|
||||
namespace nu {
|
||||
constexpr auto dimensionless = natural_unit<std::int64_t>();
|
||||
|
||||
// ----- mass -----
|
||||
|
||||
constexpr auto picogram = natural_unit<std::int64_t>::from_bu(detail::bu::picogram);
|
||||
constexpr auto nanogram = natural_unit<std::int64_t>::from_bu(detail::bu::nanogram);
|
||||
constexpr auto microgram = natural_unit<std::int64_t>::from_bu(detail::bu::microgram);
|
||||
constexpr auto milligram = natural_unit<std::int64_t>::from_bu(detail::bu::milligram);
|
||||
constexpr auto gram = natural_unit<std::int64_t>::from_bu(detail::bu::gram);
|
||||
constexpr auto kilogram = natural_unit<std::int64_t>::from_bu(detail::bu::kilogram);
|
||||
constexpr auto tonne = natural_unit<std::int64_t>::from_bu(detail::bu::tonne);
|
||||
constexpr auto kilotonne = natural_unit<std::int64_t>::from_bu(detail::bu::kilotonne);
|
||||
constexpr auto megatonne = natural_unit<std::int64_t>::from_bu(detail::bu::megatonne);
|
||||
constexpr auto gigatonne = natural_unit<std::int64_t>::from_bu(detail::bu::gigatonne);
|
||||
|
||||
// ----- distance -----
|
||||
|
||||
constexpr auto picometer = natural_unit<std::int64_t>::from_bu(detail::bu::picometer);
|
||||
constexpr auto nanometer = natural_unit<std::int64_t>::from_bu(detail::bu::nanometer);
|
||||
constexpr auto micrometer = natural_unit<std::int64_t>::from_bu(detail::bu::micrometer);
|
||||
constexpr auto millimeter = natural_unit<std::int64_t>::from_bu(detail::bu::millimeter);
|
||||
constexpr auto meter = natural_unit<std::int64_t>::from_bu(detail::bu::meter);
|
||||
constexpr auto kilometer = natural_unit<std::int64_t>::from_bu(detail::bu::kilometer);
|
||||
constexpr auto megameter = natural_unit<std::int64_t>::from_bu(detail::bu::megameter);
|
||||
constexpr auto gigameter = natural_unit<std::int64_t>::from_bu(detail::bu::gigameter);
|
||||
constexpr auto lightsecond = natural_unit<std::int64_t>::from_bu(detail::bu::lightsecond);
|
||||
constexpr auto astronomicalunit = natural_unit<std::int64_t>::from_bu(detail::bu::astronomicalunit);
|
||||
|
||||
constexpr auto inch = natural_unit<std::int64_t>::from_bu(detail::bu::inch);
|
||||
constexpr auto foot = natural_unit<std::int64_t>::from_bu(detail::bu::foot);
|
||||
constexpr auto yard = natural_unit<std::int64_t>::from_bu(detail::bu::yard);
|
||||
constexpr auto mile = natural_unit<std::int64_t>::from_bu(detail::bu::mile);
|
||||
|
||||
// ----- time -----
|
||||
|
||||
constexpr auto picosecond = natural_unit<std::int64_t>::from_bu(detail::bu::picosecond);
|
||||
constexpr auto nanosecond = natural_unit<std::int64_t>::from_bu(detail::bu::nanosecond);
|
||||
constexpr auto microsecond = natural_unit<std::int64_t>::from_bu(detail::bu::microsecond);
|
||||
constexpr auto millisecond = natural_unit<std::int64_t>::from_bu(detail::bu::millisecond);
|
||||
constexpr auto second = natural_unit<std::int64_t>::from_bu(detail::bu::second);
|
||||
constexpr auto minute = natural_unit<std::int64_t>::from_bu(detail::bu::minute);
|
||||
constexpr auto hour = natural_unit<std::int64_t>::from_bu(detail::bu::hour);
|
||||
constexpr auto day = natural_unit<std::int64_t>::from_bu(detail::bu::day);
|
||||
constexpr auto week = natural_unit<std::int64_t>::from_bu(detail::bu::week);
|
||||
constexpr auto month = natural_unit<std::int64_t>::from_bu(detail::bu::month);
|
||||
constexpr auto year = natural_unit<std::int64_t>::from_bu(detail::bu::year);
|
||||
constexpr auto year250 = natural_unit<std::int64_t>::from_bu(detail::bu::year250);
|
||||
constexpr auto year360 = natural_unit<std::int64_t>::from_bu(detail::bu::year360);
|
||||
constexpr auto year365 = natural_unit<std::int64_t>::from_bu(detail::bu::year365);
|
||||
|
||||
constexpr auto currency = natural_unit<std::int64_t>::from_bu(detail::bu::currency);
|
||||
|
||||
constexpr auto price = natural_unit<std::int64_t>::from_bu(detail::bu::price);
|
||||
|
||||
constexpr auto volatility_30d = natural_unit<std::int64_t>::from_bu(detail::bu::month, power_ratio_type(-1,2));
|
||||
constexpr auto volatility_250d = natural_unit<std::int64_t>::from_bu(detail::bu::year250, power_ratio_type(-1,2));
|
||||
constexpr auto volatility_360d = natural_unit<std::int64_t>::from_bu(detail::bu::year360, power_ratio_type(-1,2));
|
||||
constexpr auto volatility_365d = natural_unit<std::int64_t>::from_bu(detail::bu::year365, power_ratio_type(-1,2));
|
||||
} /*namespace nu*/
|
||||
} /*namespace qty*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/** end natural_unit.hpp **/
|
||||
29
xo-unit/include/xo/unit/natural_unit_iostream.hpp
Normal file
29
xo-unit/include/xo/unit/natural_unit_iostream.hpp
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/** @file natural_unit_iostream.hpp
|
||||
*
|
||||
* Author: Roland Conybeare
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "natural_unit.hpp"
|
||||
#include "bpu_iostream.hpp"
|
||||
#include <iostream>
|
||||
|
||||
namespace xo {
|
||||
namespace qty {
|
||||
template <typename Int>
|
||||
inline std::ostream &
|
||||
operator<<(std::ostream & os, const natural_unit<Int> & x) {
|
||||
os << "<natural-unit [";
|
||||
for (std::size_t i=0; i<x.n_bpu(); ++i) {
|
||||
if (i > 0)
|
||||
os << ", ";
|
||||
os << x[i];
|
||||
}
|
||||
os << "]>";
|
||||
return os;
|
||||
}
|
||||
} /*namespace qty*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/** end natural_unit_iostream.hpp **/
|
||||
34
xo-unit/include/xo/unit/numeric_concept.hpp
Normal file
34
xo-unit/include/xo/unit/numeric_concept.hpp
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/* @file numeric_concept.hpp */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <concepts>
|
||||
|
||||
namespace xo {
|
||||
namespace qty {
|
||||
/** @concept numeric_concept
|
||||
* @brief Concept for values that participate in arithmetic operations (+,-,*,/) and comparisons
|
||||
*
|
||||
* Intended to include at least:
|
||||
* - built-in integral and floating-point types
|
||||
* - xo::raio<U>
|
||||
* - xo::unit::quantity<U,R>
|
||||
*
|
||||
* Intend numeric_concept to apply to types suitable for
|
||||
* xo::unit::quantity::repr_type.
|
||||
**/
|
||||
template <typename T, typename U = T>
|
||||
concept numeric_concept = requires(T x, U y)
|
||||
{
|
||||
{ -x };
|
||||
{ x - y };
|
||||
{ x + y };
|
||||
{ x * y };
|
||||
{ x / y };
|
||||
{ x == y };
|
||||
{ x != y };
|
||||
};
|
||||
} /*namespace qty*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end numeric_concept.hpp */
|
||||
1018
xo-unit/include/xo/unit/quantity.hpp
Normal file
1018
xo-unit/include/xo/unit/quantity.hpp
Normal file
File diff suppressed because it is too large
Load diff
28
xo-unit/include/xo/unit/quantity_concept.hpp
Normal file
28
xo-unit/include/xo/unit/quantity_concept.hpp
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/** @file quantity_concept.hpp **/
|
||||
|
||||
#pragma once
|
||||
|
||||
//#include "unit_concept.hpp"
|
||||
#include "numeric_concept.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace qty {
|
||||
template <typename Quantity>
|
||||
concept quantity_concept = requires(Quantity qty, typename Quantity::repr_type repr)
|
||||
{
|
||||
typename Quantity::unit_type;
|
||||
typename Quantity::repr_type;
|
||||
|
||||
//{ Quantity::multiply(qty, qty) };
|
||||
|
||||
{ qty.scale() } -> std::same_as<const typename Quantity::repr_type &>;
|
||||
{ qty.unit() } -> std::same_as<const typename Quantity::unit_type &>;
|
||||
//{ Quantity::unit_cstr() } -> std::same_as<char const *>;
|
||||
//{ Quantity::unit_quantity() } -> std::same_as<Quantity>;
|
||||
//{ Quantity::promote(repr) } -> std::same_as<Quantity>;
|
||||
} && (true //unit_concept<typename Quantity::unit_type>
|
||||
&& numeric_concept<typename Quantity::repr_type>);
|
||||
} /*namespace qty*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end quantity_concept.hpp */
|
||||
26
xo-unit/include/xo/unit/quantity_iostream.hpp
Normal file
26
xo-unit/include/xo/unit/quantity_iostream.hpp
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/** @file quantity_iostream.hpp
|
||||
*
|
||||
* Author: Roland Conybeare
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "quantity.hpp"
|
||||
#include "natural_unit_iostream.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace qty {
|
||||
template < auto NaturalUnit, typename Repr >
|
||||
inline std::ostream &
|
||||
operator<< (std::ostream & os,
|
||||
const quantity<NaturalUnit, Repr> & x)
|
||||
{
|
||||
os << x.scale() << x.abbrev();
|
||||
return os;
|
||||
}
|
||||
|
||||
} /*namespace qty*/
|
||||
|
||||
} /*namespace xo*/
|
||||
|
||||
/** end quantity_iostream.hpp **/
|
||||
37
xo-unit/include/xo/unit/quantity_ops.hpp
Normal file
37
xo-unit/include/xo/unit/quantity_ops.hpp
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/** @file quantity_ops.hpp
|
||||
*
|
||||
* Author: Roland Conybeare
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "quantity_concept.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace qty {
|
||||
/** note: won't have constexpr result until c++26 (when @c sqrt(), @c pow() are constexpr)
|
||||
**/
|
||||
template <typename Quantity, typename Quantity2>
|
||||
requires quantity_concept<Quantity> && quantity_concept<Quantity2>
|
||||
constexpr auto
|
||||
operator== (const Quantity & x, const Quantity2 & y)
|
||||
{
|
||||
return (Quantity::compare(x, y) == 0);
|
||||
}
|
||||
|
||||
/** note: won't have constexpr result until c++26 (when @c sqrt(), @c pow() are constexpr)
|
||||
**/
|
||||
template <typename Quantity, typename Quantity2>
|
||||
requires quantity_concept<Quantity> && quantity_concept<Quantity2>
|
||||
constexpr auto
|
||||
operator<=> (const Quantity & x, const Quantity2 & y)
|
||||
{
|
||||
return Quantity::compare(x, y);
|
||||
}
|
||||
|
||||
} /*namespace qty*/
|
||||
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/** end quantity_ops.hpp **/
|
||||
401
xo-unit/include/xo/unit/scaled_unit.hpp
Normal file
401
xo-unit/include/xo/unit/scaled_unit.hpp
Normal file
|
|
@ -0,0 +1,401 @@
|
|||
/** @file scaled_unit.hpp
|
||||
*
|
||||
* Author: Roland Conybeare
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "width2x.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace qty {
|
||||
/** @class scaled_unit
|
||||
* @brief Represents the product sqrt(outer_scale_sq) * outer_scale_exact * nat_unit
|
||||
**/
|
||||
template < typename Int,
|
||||
typename OuterScale = ratio::ratio<Int> >
|
||||
struct scaled_unit {
|
||||
/** @defgroup scaled-unit-type-traits scaled-unit type traits **/
|
||||
///@{
|
||||
|
||||
/** type for representing individual basis-unit scalefactors **/
|
||||
using ratio_int_type = typename natural_unit<Int>::ratio_int_type;
|
||||
|
||||
///@}
|
||||
|
||||
public:
|
||||
/** @defgroup scaled-unit-ctors scaled-unit constructors **/
|
||||
///@{
|
||||
|
||||
/** create scaled unit representing a multiple
|
||||
* @p outer_scale_factor * @p sqrt(outer_scale_sq)
|
||||
* of natural unit @p nat_unit
|
||||
**/
|
||||
constexpr scaled_unit(const natural_unit<Int> & nat_unit,
|
||||
OuterScale outer_scale_factor,
|
||||
double outer_scale_sq)
|
||||
: natural_unit_{nat_unit},
|
||||
outer_scale_factor_{outer_scale_factor},
|
||||
outer_scale_sq_{outer_scale_sq}
|
||||
{}
|
||||
|
||||
///@}
|
||||
|
||||
/** @defgroup scaled-unit-access-methods scaled-unit access methods **/
|
||||
///@{
|
||||
|
||||
/** always true for scaled_unit **/
|
||||
static constexpr bool is_scaled_unit_type_v = true;
|
||||
|
||||
/** always true for scaled_unit **/
|
||||
constexpr bool is_scaled_unit_type() const { return true; }
|
||||
|
||||
/** true iff scaled unit can be faithfully represented by a @ref natural_unit **/
|
||||
constexpr bool is_natural() const {
|
||||
return (outer_scale_factor_ == OuterScale(1) && (outer_scale_sq_ == 1.0));
|
||||
}
|
||||
|
||||
/** true if this scaled unit has no dimension **/
|
||||
constexpr bool is_dimensionless() const { return natural_unit_.is_dimensionless(); }
|
||||
|
||||
/** get number of distinct native dimensions present.
|
||||
* e.g. for unit Newton = 1 kg.m.s^-2, n_bpu would be 3,
|
||||
* with {mass, distance, time} present.
|
||||
* Note that this value does not count exponents
|
||||
**/
|
||||
constexpr std::size_t n_bpu() const { return natural_unit_.n_bpu(); }
|
||||
|
||||
///@}
|
||||
|
||||
/** @defgroup scaled-unit-general-methods scaled-unit access methods **/
|
||||
///@{
|
||||
|
||||
/** return reciprocal of this unit. **/
|
||||
constexpr scaled_unit reciprocal() const {
|
||||
return scaled_unit(natural_unit_.reciprocal(),
|
||||
1 / outer_scale_factor_,
|
||||
1.0 / outer_scale_sq_);
|
||||
}
|
||||
|
||||
/** get bpu for dimension @p d. if d isn't present, construct bpu with 0 power **/
|
||||
constexpr bpu<Int> lookup_dim(dimension d) const {
|
||||
return natural_unit_.lookup_dim(d);
|
||||
}
|
||||
|
||||
/** return @p i'th bpu associated with this unit **/
|
||||
constexpr bpu<Int> & operator[](std::size_t i) { return natural_unit_[i]; }
|
||||
/** return @p i'th bpu associated with this unit (const version) **/
|
||||
constexpr const bpu<Int> & operator[](std::size_t i) const { return natural_unit_[i]; }
|
||||
|
||||
///@}
|
||||
|
||||
public: /* public members so scaled_unit instance can be a non-type template parameter (a structural type) */
|
||||
|
||||
/** @defgroup scaled-unit-instance-vars **/
|
||||
///@{
|
||||
|
||||
/** scale factor multiplying @ref natural_unit_ **/
|
||||
OuterScale outer_scale_factor_;
|
||||
|
||||
/** squared scale factor multiplying @ref natural_unit_ **/
|
||||
double outer_scale_sq_;
|
||||
|
||||
/** natural unit term in this scaled unit **/
|
||||
natural_unit<Int> natural_unit_;
|
||||
|
||||
///@}
|
||||
};
|
||||
|
||||
// TODO: comparison operators
|
||||
|
||||
namespace detail {
|
||||
/** promote natural unit to scaled unit (with unit outer scalefactors) **/
|
||||
template <typename Int>
|
||||
constexpr auto su_promote(const natural_unit<Int> & bpuv) {
|
||||
return scaled_unit<Int>(bpuv,
|
||||
ratio::ratio<Int>(1, 1),
|
||||
1.0);
|
||||
}
|
||||
}
|
||||
|
||||
namespace u {
|
||||
/* values here can be used as template arguments to quantity:
|
||||
* e.g.
|
||||
* quantity<u:picogram> qty1;
|
||||
* quantity<u:meter/u:second> velocity;
|
||||
*/
|
||||
|
||||
constexpr auto
|
||||
su_from_bu(const basis_unit & bu,
|
||||
const power_ratio_type & power = power_ratio_type(1))
|
||||
{
|
||||
return detail::su_promote(natural_unit<std::int64_t>::from_bu(bu, power));
|
||||
}
|
||||
|
||||
/** @defgroup scaled-unit-dimensionless scaled-unit dimensionless constant **/
|
||||
///@{
|
||||
|
||||
/** dimensionless unit; equivalent to 1 **/
|
||||
constexpr auto dimensionless = detail::su_promote(natural_unit<std::int64_t>());
|
||||
|
||||
///@}
|
||||
|
||||
// ----- mass units -----
|
||||
|
||||
/** @defgroup scaled-unit-mass scaled-unit mass units **/
|
||||
///@{
|
||||
|
||||
/** unit of 10^-12 grams **/
|
||||
constexpr auto picogram = su_from_bu(detail::bu::picogram);
|
||||
/** unit of 10^-9 grams **/
|
||||
constexpr auto nanogram = su_from_bu(detail::bu::nanogram);
|
||||
/** unit of 10^-6 grams **/
|
||||
constexpr auto microgram = su_from_bu(detail::bu::microgram);
|
||||
/** unit of 10^-3 grams **/
|
||||
constexpr auto milligram = su_from_bu(detail::bu::milligram);
|
||||
/** unit of 1 gram **/
|
||||
constexpr auto gram = su_from_bu(detail::bu::gram);
|
||||
/** unit of 10^3 grams **/
|
||||
constexpr auto kilogram = su_from_bu(detail::bu::kilogram);
|
||||
/** unit of 1 metric tonne = 10^3 kg **/
|
||||
constexpr auto tonne = su_from_bu(detail::bu::tonne);
|
||||
/** unit of 10^3 tonnes = 10^6 kg **/
|
||||
constexpr auto kilotonne = su_from_bu(detail::bu::kilotonne);
|
||||
/** unit of 10^6 tonnes = 10^9 kg **/
|
||||
constexpr auto megatonne = su_from_bu(detail::bu::megatonne);
|
||||
/** unit of 10^9 tonnes = 10^12 kg **/
|
||||
constexpr auto gigatonne = su_from_bu(detail::bu::gigatonne);
|
||||
|
||||
///@}
|
||||
|
||||
// ----- distance units -----
|
||||
|
||||
/** @defgroup scaled-unit-distance scaled-unit distance units **/
|
||||
///@{
|
||||
|
||||
/** unit of 10^-12 meters **/
|
||||
constexpr auto picometer = su_from_bu(detail::bu::picometer);
|
||||
/** unit of 10^-9 meters **/
|
||||
constexpr auto nanometer = su_from_bu(detail::bu::nanometer);
|
||||
/** unit of 10^-6 meters **/
|
||||
constexpr auto micrometer = su_from_bu(detail::bu::micrometer);
|
||||
/** unit of 10^-3 meters **/
|
||||
constexpr auto millimeter = su_from_bu(detail::bu::millimeter);
|
||||
/** unit of 1 meter **/
|
||||
constexpr auto meter = su_from_bu(detail::bu::meter);
|
||||
/** unit of 10^3 meters **/
|
||||
constexpr auto kilometer = su_from_bu(detail::bu::kilometer);
|
||||
/** unit of 10^6 meters (not commonly used) **/
|
||||
constexpr auto megameter = su_from_bu(detail::bu::megameter);
|
||||
/** unit of 10^9 meters (not commonly used) **/
|
||||
constexpr auto gigameter = su_from_bu(detail::bu::gigameter);
|
||||
|
||||
/** unit of 1 light-second = distance light travels in a vacuum in 1 second **/
|
||||
constexpr auto lightsecond = su_from_bu(detail::bu::lightsecond);
|
||||
/** unit of 1 astronomical unit, for approximate radius of earth orbit **/
|
||||
constexpr auto astronomicalunit = su_from_bu(detail::bu::astronomicalunit);
|
||||
|
||||
/** unit of 1 inch = 1/12 feet **/
|
||||
constexpr auto inch = su_from_bu(detail::bu::inch);
|
||||
/** unit of 1 foot = 0.3048 meters **/
|
||||
constexpr auto foot = su_from_bu(detail::bu::foot);
|
||||
/** unit of 1 yard = 3 feet **/
|
||||
constexpr auto yard = su_from_bu(detail::bu::yard);
|
||||
/** unit of 1 mile = 1760 yards **/
|
||||
constexpr auto mile = su_from_bu(detail::bu::mile);
|
||||
|
||||
///@}
|
||||
|
||||
// ----- time units -----
|
||||
|
||||
/** @defgroup scaled-unit-time scaled-unit time units **/
|
||||
///@{
|
||||
|
||||
/** unit of 1 picosecond = 10^-12 seconds **/
|
||||
constexpr auto picosecond = su_from_bu(detail::bu::picosecond);
|
||||
/** unit of 1 nanosecond = 10^-9 seconds **/
|
||||
constexpr auto nanosecond = su_from_bu(detail::bu::nanosecond);
|
||||
/** unit of 1 microseccond = 10^-6 seconds **/
|
||||
constexpr auto microsecond = su_from_bu(detail::bu::microsecond);
|
||||
/** unit of 1 millisecond = 10^-3 seconds **/
|
||||
constexpr auto millisecond = su_from_bu(detail::bu::millisecond);
|
||||
/** unit of 1 second **/
|
||||
constexpr auto second = su_from_bu(detail::bu::second);
|
||||
/** unit of 1 minute **/
|
||||
constexpr auto minute = su_from_bu(detail::bu::minute);
|
||||
/** unit of 1 hour **/
|
||||
constexpr auto hour = su_from_bu(detail::bu::hour);
|
||||
/** unit for a 24-hour day **/
|
||||
constexpr auto day = su_from_bu(detail::bu::day);
|
||||
/** unit for a week comprising exactly 7 24-hour days **/
|
||||
constexpr auto week = su_from_bu(detail::bu::week);
|
||||
/** unit for a 30-day month **/
|
||||
constexpr auto month = su_from_bu(detail::bu::month);
|
||||
/** unit for a year containing exactly 365.25 24-hour days **/
|
||||
constexpr auto year = su_from_bu(detail::bu::year);
|
||||
/** unit for a 'year' containing exactly 250 24-hour days.
|
||||
* (approximates the number of business days in a year)
|
||||
**/
|
||||
constexpr auto year250 = su_from_bu(detail::bu::year250);
|
||||
/** unit for a 'year' containing exactly 360 24-hour days **/
|
||||
constexpr auto year360 = su_from_bu(detail::bu::year360);
|
||||
/** unit for a 'year' containing exactly 365 24-hour days **/
|
||||
constexpr auto year365 = su_from_bu(detail::bu::year365);
|
||||
|
||||
///@}
|
||||
|
||||
/** @defgroup scaled-unit-misc scaled-unit miscellaneous units **/
|
||||
///@{
|
||||
|
||||
// ----- currency -----
|
||||
|
||||
/** generic currency unit **/
|
||||
constexpr auto currency = su_from_bu(detail::bu::currency);
|
||||
|
||||
// ----- price - ---
|
||||
|
||||
/** generic price unit **/
|
||||
constexpr auto price = su_from_bu(detail::bu::price);
|
||||
|
||||
///@}
|
||||
|
||||
// ----- volatility units -----
|
||||
|
||||
/** @defgroup scaled-unit-volatility scaled-unit volatility units **/
|
||||
///@{
|
||||
|
||||
/** volatility, in 30-day units **/
|
||||
constexpr auto volatility_30d = su_from_bu(detail::bu::month,
|
||||
power_ratio_type(-1,2));
|
||||
/** volatility, in 250-day 'annual' units **/
|
||||
constexpr auto volatility_250d = su_from_bu(detail::bu::year250,
|
||||
power_ratio_type(-1,2));
|
||||
/** volatility, in 360-day 'annual' units **/
|
||||
constexpr auto volatility_360d = su_from_bu(detail::bu::year360,
|
||||
power_ratio_type(-1,2));
|
||||
/** volatility, in 365-day 'annual' units **/
|
||||
constexpr auto volatility_365d = su_from_bu(detail::bu::year365,
|
||||
power_ratio_type(-1,2));
|
||||
///@}
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template <typename Int,
|
||||
typename Int2x = width2x<Int>,
|
||||
typename OuterScale = ratio::ratio<Int2x>>
|
||||
constexpr
|
||||
scaled_unit<Int, OuterScale>
|
||||
su_product(const natural_unit<Int> & lhs_bpu_array,
|
||||
const natural_unit<Int> & rhs_bpu_array)
|
||||
{
|
||||
natural_unit<Int2x> prod = lhs_bpu_array.template to_repr<Int2x>();
|
||||
|
||||
/* accumulate product of scalefactors spun off by rescaling
|
||||
* any basis-units in rhs_bpu_array that conflict with the same dimension
|
||||
* in lh_bpu_array
|
||||
*/
|
||||
auto sfr = (detail::outer_scalefactor_result<Int2x>
|
||||
(OuterScale(1) /*outer_scale_factor*/,
|
||||
1.0 /*outer_scale_sq*/));
|
||||
|
||||
for (std::size_t i = 0; i < rhs_bpu_array.n_bpu(); ++i) {
|
||||
auto sfr2 = nu_product_inplace<Int2x, OuterScale>(&prod,
|
||||
rhs_bpu_array[i].template to_repr<Int2x>());
|
||||
|
||||
sfr.outer_scale_factor_ = sfr.outer_scale_factor_ * sfr2.outer_scale_factor_;
|
||||
sfr.outer_scale_sq_ *= sfr2.outer_scale_sq_;
|
||||
}
|
||||
|
||||
return scaled_unit<Int, OuterScale>(prod.template to_repr<Int>(),
|
||||
sfr.outer_scale_factor_,
|
||||
sfr.outer_scale_sq_);
|
||||
}
|
||||
|
||||
/* use Int2x to accumulate scalefactor
|
||||
*/
|
||||
template < typename Int,
|
||||
typename Int2x = width2x<Int>,
|
||||
typename OuterScale = ratio::ratio<Int2x> >
|
||||
constexpr
|
||||
scaled_unit<Int, OuterScale>
|
||||
su_ratio(const natural_unit<Int> & nu_lhs,
|
||||
const natural_unit<Int> & nu_rhs)
|
||||
{
|
||||
natural_unit<Int2x> ratio = nu_lhs.template to_repr<Int2x>();
|
||||
|
||||
/* accumulate product of scalefactors spun off by rescaling
|
||||
* any basis-units in rhs_bpu_array that conflict with the same dimension
|
||||
* in lh_bpu_array
|
||||
*/
|
||||
auto sfr = (detail::outer_scalefactor_result<Int2x, OuterScale>
|
||||
(OuterScale(1) /*outer_scale_factor*/,
|
||||
1.0 /*outer_scale_sq*/));
|
||||
|
||||
for (std::size_t i = 0; i < nu_rhs.n_bpu(); ++i) {
|
||||
auto sfr2 = nu_ratio_inplace<Int2x, OuterScale>(&ratio,
|
||||
nu_rhs[i].template to_repr<Int2x>());
|
||||
|
||||
/* note: nu_ratio_inplace() reports multiplicative outer scaling factors,
|
||||
* so multiply is correct here
|
||||
*/
|
||||
sfr.outer_scale_factor_ = (sfr.outer_scale_factor_
|
||||
* sfr2.outer_scale_factor_);
|
||||
sfr.outer_scale_sq_ *= sfr2.outer_scale_sq_;
|
||||
}
|
||||
|
||||
return scaled_unit<Int, OuterScale>(ratio.template to_repr<Int>(),
|
||||
sfr.outer_scale_factor_,
|
||||
sfr.outer_scale_sq_);
|
||||
}
|
||||
}
|
||||
|
||||
/** @defgroup scaled-unit-operators **/
|
||||
///@{
|
||||
|
||||
/** Multiply scaled_unit instances @p x_unit and @p y_unit.
|
||||
* Result is a scaled_unit for the product dimension.
|
||||
* For each basis dimension, result will prioritize scale from @p x_unit ahead of @p y_unit.
|
||||
**/
|
||||
template <typename Int,
|
||||
typename Int2x = detail::width2x_t<Int>>
|
||||
inline constexpr scaled_unit<Int>
|
||||
operator* (const scaled_unit<Int> & x_unit,
|
||||
const scaled_unit<Int> & y_unit)
|
||||
{
|
||||
auto rr = detail::su_product<Int, Int2x>(x_unit.natural_unit_,
|
||||
y_unit.natural_unit_);
|
||||
|
||||
return (scaled_unit<Int>
|
||||
(rr.natural_unit_,
|
||||
(ratio::ratio<Int2x>(rr.outer_scale_factor_)
|
||||
* ratio::ratio<Int2x>(x_unit.outer_scale_factor_)
|
||||
* ratio::ratio<Int2x>(y_unit.outer_scale_factor_)),
|
||||
rr.outer_scale_sq_ * x_unit.outer_scale_sq_ * y_unit.outer_scale_sq_));
|
||||
}
|
||||
|
||||
/** Divide scaled_unit instances @p x_unit by @p y_unit.
|
||||
* Result is a scaled_unit for the quotient dimension.
|
||||
* For each basis dimension, result will prioritize scale from @p x_unit ahead of @p y_unit.
|
||||
**/
|
||||
template <typename Int,
|
||||
typename Int2x = detail::width2x_t<Int>>
|
||||
inline constexpr scaled_unit<Int>
|
||||
operator/ (const scaled_unit<Int> & x_unit,
|
||||
const scaled_unit<Int> & y_unit)
|
||||
{
|
||||
auto rr = detail::su_ratio<Int, Int2x>(x_unit.natural_unit_,
|
||||
y_unit.natural_unit_);
|
||||
|
||||
return (scaled_unit<Int>
|
||||
(rr.natural_unit_,
|
||||
(ratio::ratio<Int2x>(rr.outer_scale_factor_)
|
||||
* ratio::ratio<Int2x>(x_unit.outer_scale_factor_)
|
||||
* ratio::ratio<Int2x>(y_unit.outer_scale_factor_)),
|
||||
rr.outer_scale_sq_ * x_unit.outer_scale_sq_ * y_unit.outer_scale_sq_));
|
||||
}
|
||||
|
||||
///@}
|
||||
} /*namespace qty*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/** end scaled_unit.hpp **/
|
||||
23
xo-unit/include/xo/unit/scaled_unit_concept.hpp
Normal file
23
xo-unit/include/xo/unit/scaled_unit_concept.hpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/** @file scaled_unit_concept.hpp **/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <concepts>
|
||||
|
||||
namespace xo {
|
||||
namespace qty {
|
||||
template <typename ScaledUnit>
|
||||
concept scaled_unit_concept = requires(ScaledUnit su)
|
||||
{
|
||||
typename ScaledUnit::ratio_int_type;
|
||||
|
||||
{ su.is_scaled_unit_type() } -> std::same_as<bool>;
|
||||
{ su.is_natural() } -> std::same_as<bool>;
|
||||
{ su.is_dimensionless() } -> std::same_as<bool>;
|
||||
|
||||
} && ScaledUnit::is_scaled_unit_type_v;
|
||||
} /*namespace qty*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/** end scaled_unit_concept.hpp **/
|
||||
31
xo-unit/include/xo/unit/scaled_unit_iostream.hpp
Normal file
31
xo-unit/include/xo/unit/scaled_unit_iostream.hpp
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/** @file scaled_unit_iostream.hpp
|
||||
*
|
||||
* Author: Roland Conybeare
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "scaled_unit.hpp"
|
||||
#include "natural_unit_iostream.hpp"
|
||||
#include "xo/flatstring/int128_iostream.hpp"
|
||||
#include <iostream>
|
||||
|
||||
namespace xo {
|
||||
namespace qty {
|
||||
template <typename Int, typename OuterScale>
|
||||
inline std::ostream &
|
||||
operator<<(std::ostream & os,
|
||||
const scaled_unit<Int, OuterScale> & x)
|
||||
{
|
||||
os << "<scaled-unit"
|
||||
<< xtag("outer_scale_factor", x.outer_scale_factor_)
|
||||
<< xtag("outer_scale_sq", x.outer_scale_sq_)
|
||||
<< xtag("bpuv", x.natural_unit_)
|
||||
<< ">";
|
||||
|
||||
return os;
|
||||
};
|
||||
} /*namespace qty*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/** end scaled_unit_iostream.hpp **/
|
||||
24
xo-unit/include/xo/unit/unit2.hpp
Normal file
24
xo-unit/include/xo/unit/unit2.hpp
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/** @file unit2.hpp
|
||||
*
|
||||
* Author: Roland Conybeare
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "natural_unit.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace qty {
|
||||
/** @class unit2
|
||||
* @brief represent an arbitrary unit along with dimension details
|
||||
*
|
||||
* For example,
|
||||
* kg.m.s^-2 or
|
||||
* (kilogram * meter) / (second * second)
|
||||
**/
|
||||
template <typename Int>
|
||||
using unit2 = natural_unit<Int>;
|
||||
} /*namespace qty*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/** end unit2.hpp **/
|
||||
39
xo-unit/include/xo/unit/width2x.hpp
Normal file
39
xo-unit/include/xo/unit/width2x.hpp
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/** @file width2x.hpp
|
||||
*
|
||||
* Author: Roland Conybeare
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "natural_unit.hpp"
|
||||
#include <cstdint>
|
||||
|
||||
namespace xo {
|
||||
namespace qty {
|
||||
namespace detail {
|
||||
template <typename Int>
|
||||
struct width2x;
|
||||
|
||||
template <>
|
||||
struct width2x<std::int16_t> {
|
||||
using type = std::int32_t;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct width2x<std::int32_t> {
|
||||
using type = std::int64_t;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct width2x<std::int64_t> {
|
||||
using type = __int128_t;
|
||||
};
|
||||
|
||||
template <typename Int>
|
||||
using width2x_t = width2x<Int>::type;
|
||||
}
|
||||
|
||||
} /*namespace qty*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/** end width2x.hpp **/
|
||||
562
xo-unit/include/xo/unit/xquantity.hpp
Normal file
562
xo-unit/include/xo/unit/xquantity.hpp
Normal file
|
|
@ -0,0 +1,562 @@
|
|||
/** @file xquantity.hpp
|
||||
*
|
||||
* Author: Roland Conybeare
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "quantity_ops.hpp"
|
||||
#include "scaled_unit.hpp"
|
||||
#include "natural_unit.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace qty {
|
||||
/** @class xquantity
|
||||
* @brief represent a scalar quantity with polymorphic units.
|
||||
*
|
||||
* - @p Repr type used represent a dimensionless multiple of a natural unit.
|
||||
*
|
||||
* Constexpr implementation, but units are explicitly represented:
|
||||
* @code
|
||||
* sizeof(xquantity) > sizeof(xquantity::repr_type)
|
||||
* @endcode
|
||||
*
|
||||
* Explicit unit representation allows introducing units at runtime,
|
||||
* for example in python bindings.
|
||||
* See for example <a href="https://github.com/rconybea/xo-pyutil">xo-pyutil</a>
|
||||
*
|
||||
* See @ref quantity for implementation with units established at compile time
|
||||
*
|
||||
* Require:
|
||||
* - Repr supports numeric operations (+, -, *, /)
|
||||
* - Repr supports conversion from double.
|
||||
**/
|
||||
template <typename Repr = double,
|
||||
typename Int = std::int64_t>
|
||||
class xquantity {
|
||||
public:
|
||||
/** @defgroup xquantity-type-traits xquantity type traits **/
|
||||
///@{
|
||||
/** @brief runtime representation for this value's scale **/
|
||||
using repr_type = Repr;
|
||||
/** @brief runtime representation for this value's unit **/
|
||||
using unit_type = natural_unit<Int>;
|
||||
/** @brief type used for numerator and denominator in basis-unit scalefactor ratios **/
|
||||
using ratio_int_type = Int;
|
||||
/** @brief double-width type for numerator and denominator of intermediate
|
||||
* scalefactor ratios. Use to mitigate loss of precision during computation
|
||||
* of conversion factors between units with widely-differing magnitude
|
||||
**/
|
||||
using ratio_int2x_type = detail::width2x_t<typename unit_type::ratio_int_type>;
|
||||
///@}
|
||||
|
||||
public:
|
||||
/** @defgroup xquantity-ctors xquantity constructors **/
|
||||
///@{
|
||||
|
||||
/** create dimensionless, zero quantity **/
|
||||
constexpr xquantity()
|
||||
: scale_{0}, unit_{natural_unit<Int>()} {}
|
||||
/** create quantity representing multiple of @p scale times @p unit **/
|
||||
constexpr xquantity(Repr scale,
|
||||
const natural_unit<Int> & unit)
|
||||
: scale_{scale}, unit_{unit} {}
|
||||
/** create quantity representing multiple of @p scale times @p unit.
|
||||
*
|
||||
* Collects outer scalefactors (if any) from @p unit,
|
||||
* so for example:
|
||||
*
|
||||
* @code
|
||||
* using namespace xo::qty;
|
||||
* xquantity q(123, u::meter * u::millimeter);
|
||||
*
|
||||
* q.scale() --> 0.123
|
||||
* @endcode
|
||||
**/
|
||||
constexpr xquantity(Repr scale,
|
||||
const scaled_unit<Int> & unit)
|
||||
:
|
||||
scale_(scale
|
||||
* unit.outer_scale_factor_.template convert_to<double>()
|
||||
* ((unit.outer_scale_sq_ == 1.0)
|
||||
? 1.0
|
||||
: ::sqrt(unit.outer_scale_sq_))
|
||||
),
|
||||
unit_{unit.natural_unit_} {}
|
||||
|
||||
///@}
|
||||
|
||||
/** @defgroup xquantity-constants static xquantity constants **/
|
||||
///@{
|
||||
|
||||
/** false since unit information may be unknown at compile time.
|
||||
* Coordinates with @c quantity::always_constexpr_unit
|
||||
**/
|
||||
static constexpr bool always_constexpr_unit = false;
|
||||
|
||||
///@}
|
||||
|
||||
/** @defgroup xquantity-access-methods xquantity access methods **/
|
||||
///@{
|
||||
|
||||
/** get member @ref scale_ **/
|
||||
constexpr const repr_type & scale() const { return scale_; }
|
||||
/** get member @ref unit_ **/
|
||||
constexpr const unit_type & unit() const { return unit_; }
|
||||
|
||||
/** true iff this quantity has no dimension **/
|
||||
constexpr bool is_dimensionless() const { return unit_.is_dimensionless(); }
|
||||
|
||||
/** return abbreviation for quantities with this unit **/
|
||||
constexpr nu_abbrev_type abbrev() const { return unit_.abbrev(); }
|
||||
|
||||
///@}
|
||||
|
||||
/** @defgroup xquantity-arithmetic-support**/
|
||||
///@{
|
||||
|
||||
/** create unit quantity with same unit as @c this **/
|
||||
constexpr xquantity unit_qty() const { return xquantity(1, unit_); }
|
||||
|
||||
/** create zero quantity with same unit as @c this **/
|
||||
constexpr xquantity zero_qty() const { return xquantity(0, unit_); }
|
||||
|
||||
/** create quantity representing reciprocal of @c this **/
|
||||
constexpr xquantity reciprocal() const { return xquantity(1.0 / scale_, unit_.reciprocal()); }
|
||||
|
||||
/** create quantity representing this value scaled by dimensionless mutliplier @p x **/
|
||||
template <typename Dimensionless>
|
||||
requires std::is_arithmetic_v<Dimensionless>
|
||||
constexpr auto scale_by(Dimensionless x) const {
|
||||
return xquantity(x * this->scale_, this->unit_);
|
||||
}
|
||||
|
||||
/** create quantity representing this value scaled by dimensionless multiplier @p 1/x **/
|
||||
template <typename Dimensionless>
|
||||
requires std::is_arithmetic_v<Dimensionless>
|
||||
constexpr auto divide_by(Dimensionless x) const {
|
||||
return xquantity(this->scale_ / x, this->unit_);
|
||||
}
|
||||
|
||||
/** create quantity representing dimensionless numerator @p x divided by this value **/
|
||||
template <typename Dimensionless>
|
||||
requires std::is_arithmetic_v<Dimensionless>
|
||||
constexpr auto divide_into(Dimensionless x) const {
|
||||
return xquantity(x / this->scale_, this->unit_.reciprocal());
|
||||
}
|
||||
|
||||
/** multiply two @c xquantity values, or a mixed (@c xquantity, @c quantity) pair **/
|
||||
template <typename Quantity2>
|
||||
static constexpr
|
||||
auto multiply(const xquantity & x, const Quantity2 & y) {
|
||||
using r_repr_type = std::common_type_t<typename xquantity::repr_type,
|
||||
typename Quantity2::repr_type>;
|
||||
using r_int_type = std::common_type_t<typename xquantity::ratio_int_type,
|
||||
typename Quantity2::ratio_int_type>;
|
||||
using r_int2x_type = std::common_type_t<typename xquantity::ratio_int2x_type,
|
||||
typename Quantity2::ratio_int2x_type>;
|
||||
|
||||
auto rr = detail::su_product<r_int_type, r_int2x_type>(x.unit(), y.unit());
|
||||
|
||||
r_repr_type r_scale = (::sqrt(rr.outer_scale_sq_)
|
||||
* rr.outer_scale_factor_.template convert_to<r_repr_type>()
|
||||
* static_cast<r_repr_type>(x.scale())
|
||||
* static_cast<r_repr_type>(y.scale()));
|
||||
|
||||
return xquantity<r_repr_type, r_int_type>(r_scale,
|
||||
rr.natural_unit_);
|
||||
}
|
||||
|
||||
/** compute quotient @p x / @p y, where @p x and @p y are xquantities **/
|
||||
template <typename Quantity2>
|
||||
static constexpr
|
||||
auto divide(const xquantity & x, const Quantity2 & y) {
|
||||
using r_repr_type = std::common_type_t<typename xquantity::repr_type,
|
||||
typename Quantity2::repr_type>;
|
||||
using r_int_type = std::common_type_t<typename xquantity::ratio_int_type,
|
||||
typename Quantity2::ratio_int_type>;
|
||||
using r_int2x_type = std::common_type_t<typename xquantity::ratio_int2x_type,
|
||||
typename Quantity2::ratio_int2x_type>;
|
||||
|
||||
auto rr = detail::su_ratio<r_int_type, r_int2x_type>(x.unit(), y.unit());
|
||||
|
||||
/* note: su_ratio() reports multiplicative outer scaling factors,
|
||||
* so multiply is correct here
|
||||
*/
|
||||
r_repr_type r_scale = (::sqrt(rr.outer_scale_sq_)
|
||||
* rr.outer_scale_factor_.template convert_to<r_repr_type>()
|
||||
* static_cast<r_repr_type>(x.scale())
|
||||
/ static_cast<r_repr_type>(y.scale()));
|
||||
|
||||
return xquantity<r_repr_type, r_int_type>(r_scale,
|
||||
rr.natural_unit_);
|
||||
}
|
||||
|
||||
/** compute sum @p x + @p y, where @p x and @p y are xquantities **/
|
||||
template <typename Quantity2>
|
||||
static constexpr
|
||||
auto add(const xquantity & x, const Quantity2 & y) {
|
||||
using r_repr_type = std::common_type_t<typename xquantity::repr_type,
|
||||
typename Quantity2::repr_type>;
|
||||
using r_int_type = std::common_type_t<typename xquantity::ratio_int_type,
|
||||
typename Quantity2::ratio_int_type>;
|
||||
using r_int2x_type = std::common_type_t<typename xquantity::ratio_int2x_type,
|
||||
typename Quantity2::ratio_int2x_type>;
|
||||
|
||||
/* conversion to get y in same units as x: multiply by y/x */
|
||||
auto rr = detail::su_ratio<r_int_type, r_int2x_type>(y.unit(), x.unit());
|
||||
|
||||
if (rr.natural_unit_.is_dimensionless()) {
|
||||
r_repr_type r_scale = (static_cast<r_repr_type>(x.scale())
|
||||
+ (::sqrt(rr.outer_scale_sq_)
|
||||
* rr.outer_scale_factor_.template convert_to<r_repr_type>()
|
||||
* static_cast<r_repr_type>(y.scale())));
|
||||
|
||||
return xquantity<r_repr_type, r_int_type>(r_scale, x.unit_.template to_repr<r_int_type>());
|
||||
} else {
|
||||
/* units don't match! */
|
||||
return xquantity<r_repr_type, r_int_type>(std::numeric_limits<r_repr_type>::quiet_NaN(),
|
||||
x.unit_.template to_repr<r_int_type>());
|
||||
}
|
||||
}
|
||||
|
||||
/** compute difference @p x - @p y, where @p x and @p y are xquantities **/
|
||||
template <typename Quantity2>
|
||||
static constexpr
|
||||
auto subtract(const xquantity & x, const Quantity2 & y) {
|
||||
using r_repr_type = std::common_type_t<typename xquantity::repr_type,
|
||||
typename Quantity2::repr_type>;
|
||||
using r_int_type = std::common_type_t<typename xquantity::ratio_int_type,
|
||||
typename Quantity2::ratio_int_type>;
|
||||
using r_int2x_type = std::common_type_t<typename xquantity::ratio_int2x_type,
|
||||
typename Quantity2::ratio_int2x_type>;
|
||||
|
||||
/* conversion to get y in same units as x: multiply by y/x */
|
||||
auto rr = detail::su_ratio<r_int_type, r_int2x_type>(y.unit(), x.unit());
|
||||
|
||||
if (rr.natural_unit_.is_dimensionless()) {
|
||||
r_repr_type r_scale = (static_cast<r_repr_type>(x.scale())
|
||||
- (::sqrt(rr.outer_scale_sq_)
|
||||
* rr.outer_scale_factor_.template convert_to<r_repr_type>()
|
||||
* static_cast<r_repr_type>(y.scale())));
|
||||
|
||||
return xquantity<r_repr_type, r_int_type>(r_scale, x.unit_.template to_repr<r_int_type>());
|
||||
} else {
|
||||
/* units don't match! */
|
||||
return xquantity<r_repr_type, r_int_type>(std::numeric_limits<r_repr_type>::quiet_NaN(),
|
||||
x.unit_.template to_repr<r_int_type>());
|
||||
}
|
||||
}
|
||||
|
||||
///@}
|
||||
|
||||
/** @defgroup xquantity-unit-conversion **/
|
||||
///@{
|
||||
|
||||
/** create quantity representing the same value, but in units of @p unit2 **/
|
||||
constexpr
|
||||
auto rescale(const natural_unit<Int> & unit2) const {
|
||||
/* conversion factor from .unit -> unit2*/
|
||||
auto rr = detail::su_ratio<ratio_int_type,
|
||||
ratio_int2x_type>(this->unit_, unit2);
|
||||
|
||||
if (rr.natural_unit_.is_dimensionless()) {
|
||||
repr_type r_scale = (::sqrt(rr.outer_scale_sq_)
|
||||
* rr.outer_scale_factor_.template convert_to<repr_type>()
|
||||
* this->scale_);
|
||||
return xquantity(r_scale, unit2);
|
||||
} else {
|
||||
return xquantity(std::numeric_limits<repr_type>::quiet_NaN(), unit2);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr
|
||||
auto rescale_ext(const scaled_unit<Int> & unit2) const {
|
||||
/* conversion factor from .unit -> unit2*/
|
||||
auto rr = detail::su_ratio<ratio_int_type,
|
||||
ratio_int2x_type>(unit_,
|
||||
unit2.natural_unit_);
|
||||
|
||||
if (rr.natural_unit_.is_dimensionless()) {
|
||||
/* NOTE: test for unit .outer_scale_sq values to get constexpr result with c++23
|
||||
* and integer dimension powers.
|
||||
*
|
||||
* NOTE: we don't intend to support mixed-unit quantities.
|
||||
* If we change intention, will need to take into account
|
||||
* (s_scaled_unit.outer_scale_factor_, s_scaled_unit.outer_scale_sq_)
|
||||
*/
|
||||
repr_type r_scale
|
||||
= ((((rr.outer_scale_sq_ == 1.0)
|
||||
&& (unit2.outer_scale_sq_ == 1.0))
|
||||
? 1.0
|
||||
: ::sqrt(rr.outer_scale_sq_ / unit2.outer_scale_sq_))
|
||||
* rr.outer_scale_factor_.template convert_to<repr_type>()
|
||||
* this->scale_
|
||||
/ unit2.outer_scale_factor_.template convert_to<repr_type>());
|
||||
return xquantity(r_scale, unit2);
|
||||
} else {
|
||||
return xquantity(std::numeric_limits<repr_type>::quiet_NaN(), unit2);
|
||||
}
|
||||
}
|
||||
|
||||
///@}
|
||||
|
||||
/** @defgroup xquantity-comparison-support xquantity comparison support methods **/
|
||||
///@{
|
||||
|
||||
/** perform 3-way comparison between @c xquantity values @p x and @p y **/
|
||||
template <typename Quantity2>
|
||||
static constexpr
|
||||
auto compare(const xquantity & x, const Quantity2 & y) {
|
||||
xquantity y2 = y.rescale(x.unit_);
|
||||
|
||||
return x.scale() <=> y2.scale();
|
||||
}
|
||||
|
||||
///@}
|
||||
|
||||
/** @defgroup xquantity-operators xquantity operators **/
|
||||
///@{
|
||||
|
||||
/** add @p x in-place, converting units if necessary **/
|
||||
template <typename Quantity2>
|
||||
xquantity & operator+= (const Quantity2 & x) {
|
||||
*this = *this + x;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** unary negation; preserves unit information **/
|
||||
xquantity operator-() const {
|
||||
return xquantity(-scale_, unit_);
|
||||
}
|
||||
|
||||
/** subtract @p x in-place, converting units if necessary **/
|
||||
template <typename Quantity2>
|
||||
xquantity & operator-= (const Quantity2 & x) {
|
||||
*this = *this - x;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** multiply @p x in-place, converting units if necessary
|
||||
*
|
||||
* @note: unlike @c quantity::operator*=, may change dimension of lhs
|
||||
**/
|
||||
template <typename Quantity2>
|
||||
xquantity & operator*= (const Quantity2 & x) {
|
||||
*this = *this * x;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** divide @p x in-place, converting units if necessary
|
||||
*
|
||||
* @note: unlike @c quantity::operator/=, may change dimension of lhs
|
||||
**/
|
||||
template <typename Quantity2>
|
||||
xquantity & operator/= (const Quantity2 & x) {
|
||||
*this = *this / x;
|
||||
return *this;
|
||||
}
|
||||
|
||||
///@}
|
||||
|
||||
private:
|
||||
/** @defgroup xquantity-instance-vars **/
|
||||
///@{
|
||||
|
||||
/** quantity represents this multiple of a unit amount **/
|
||||
Repr scale_ = Repr{};
|
||||
/** unit for this quantity **/
|
||||
natural_unit<Int> unit_;
|
||||
|
||||
///@}
|
||||
}; /*xquantity*/
|
||||
|
||||
/** note: won't have constexpr result until c++26 (when @c sqrt(), @c pow() are constexpr)
|
||||
**/
|
||||
template <typename Repr = double,
|
||||
typename Int = std::int64_t>
|
||||
inline constexpr xquantity<Repr, Int>
|
||||
unit_qty(const scaled_unit<Int> & u)
|
||||
{
|
||||
return xquantity<Repr, Int>
|
||||
(u.outer_scale_factor_.template convert_to<double>() * ::sqrt(u.outer_scale_sq_),
|
||||
u.natural_unit_);
|
||||
}
|
||||
|
||||
/** note: won't have constexpr result until c++26 (when @c sqrt(), @c pow() are constexpr)
|
||||
**/
|
||||
template <typename Repr = double,
|
||||
typename Int = std::int64_t>
|
||||
inline constexpr xquantity<Repr, Int>
|
||||
natural_unit_qty(const natural_unit<Int> & nu) {
|
||||
return xquantity<Repr, Int>(1.0, nu);
|
||||
}
|
||||
|
||||
/** note: won't have constexpr result until c++26 (when @c sqrt(), @c pow() are constexpr)
|
||||
**/
|
||||
template <typename Q1, typename Q2>
|
||||
requires (quantity_concept<Q1>
|
||||
&& quantity_concept<Q2>
|
||||
&& (!Q1::always_constexpr_unit || !Q2::always_constexpr_unit))
|
||||
constexpr auto
|
||||
operator* (const Q1 & x, const Q2 & y)
|
||||
{
|
||||
return Q1::multiply(x, y);
|
||||
}
|
||||
|
||||
/** note: won't have constexpr result until c++26 (when ::sqrt(), ::pow() are constexpr)
|
||||
**/
|
||||
template <typename Quantity>
|
||||
requires quantity_concept<Quantity>
|
||||
constexpr auto
|
||||
operator* (double x, const Quantity & y)
|
||||
{
|
||||
return y.scale_by(x);
|
||||
}
|
||||
|
||||
/** note: won't have constexpr result until c++26 (when ::sqrt(), ::pow() are constexpr)
|
||||
**/
|
||||
template <typename Quantity>
|
||||
requires quantity_concept<Quantity>
|
||||
constexpr auto
|
||||
operator* (const Quantity & x, double y)
|
||||
{
|
||||
return x.scale_by(y);
|
||||
}
|
||||
|
||||
/** note: won't have constexpr result until c++26 (when ::sqrt(), ::pow() are constexpr)
|
||||
**/
|
||||
template <typename Quantity, typename Quantity2>
|
||||
requires quantity_concept<Quantity> && quantity_concept<Quantity2>
|
||||
constexpr auto
|
||||
operator/ (const Quantity & x, const Quantity2 & y)
|
||||
{
|
||||
return Quantity::divide(x, y);
|
||||
}
|
||||
|
||||
/** note: doesn not require unit scaling, so constexpr with c++23 **/
|
||||
template <typename Quantity, typename Dimensionless>
|
||||
requires quantity_concept<Quantity> && std::is_arithmetic_v<Dimensionless>
|
||||
constexpr auto
|
||||
operator/ (const Quantity & x, Dimensionless y)
|
||||
{
|
||||
return x.divide_by(y);
|
||||
}
|
||||
|
||||
/** note: doesn not require unit scaling, so constexpr with c++23 **/
|
||||
template <typename Dimensionless, typename Quantity>
|
||||
requires std::is_arithmetic_v<Dimensionless> && quantity_concept<Quantity>
|
||||
constexpr auto
|
||||
operator/ (Dimensionless x, const Quantity & y)
|
||||
{
|
||||
return y.divide_into(x);
|
||||
}
|
||||
|
||||
/** note: won't have constexpr result until c++26 (when ::sqrt(), ::pow() are constexpr)
|
||||
**/
|
||||
template <typename Quantity, typename Quantity2>
|
||||
requires quantity_concept<Quantity> && quantity_concept<Quantity2>
|
||||
constexpr auto
|
||||
operator+ (const Quantity & x, const Quantity2 & y)
|
||||
{
|
||||
return Quantity::add(x, y);
|
||||
}
|
||||
|
||||
/** note: won't have constexpr result until c++26 (when ::sqrt(), ::pow() are constexpr)
|
||||
**/
|
||||
template <typename Quantity>
|
||||
requires quantity_concept<Quantity>
|
||||
constexpr auto
|
||||
operator+ (const Quantity & x, double y)
|
||||
{
|
||||
return x + Quantity(y, u::dimensionless);
|
||||
}
|
||||
|
||||
/** note: won't have constexpr result until c++26 (when ::sqrt(), ::pow() are constexpr)
|
||||
**/
|
||||
template <typename Quantity>
|
||||
requires quantity_concept<Quantity>
|
||||
constexpr auto
|
||||
operator+ (double x, const Quantity & y)
|
||||
{
|
||||
return Quantity(x, u::dimensionless) + y;
|
||||
}
|
||||
|
||||
/** note: won't have constexpr result until c++26 (when ::sqrt(), ::pow() are constexpr)
|
||||
**/
|
||||
template <typename Quantity, typename Quantity2>
|
||||
requires (quantity_concept<Quantity>
|
||||
&& quantity_concept<Quantity2>)
|
||||
constexpr auto
|
||||
operator- (const Quantity & x, const Quantity2 & y)
|
||||
{
|
||||
return Quantity::subtract(x, y);
|
||||
}
|
||||
|
||||
/** note: won't have constexpr result until c++26 (when ::sqrt(), ::pow() are constexpr)
|
||||
**/
|
||||
template <typename Quantity>
|
||||
requires quantity_concept<Quantity>
|
||||
constexpr auto
|
||||
operator- (const Quantity & x, double y)
|
||||
{
|
||||
return x - Quantity(y, u::dimensionless);
|
||||
}
|
||||
|
||||
/** note: won't have constexpr result until c++26 (when ::sqrt(), ::pow() are constexpr)
|
||||
**/
|
||||
template <typename Quantity>
|
||||
requires quantity_concept<Quantity>
|
||||
constexpr auto
|
||||
operator- (double x, const Quantity & y)
|
||||
{
|
||||
return Quantity(x, u::dimensionless) - y;
|
||||
}
|
||||
|
||||
/** note: won't have constexpr result until c++26 (when ::sqrt(), ::pow() are constexpr)
|
||||
**/
|
||||
template <typename Quantity>
|
||||
requires quantity_concept<Quantity>
|
||||
constexpr auto
|
||||
operator== (const Quantity & x, double y)
|
||||
{
|
||||
return (x == Quantity(y, u::dimensionless));
|
||||
}
|
||||
|
||||
/** note: won't have constexpr result until c++26 (when ::sqrt(), ::pow() are constexpr)
|
||||
**/
|
||||
template <typename Quantity>
|
||||
requires quantity_concept<Quantity>
|
||||
constexpr auto
|
||||
operator== (double x, const Quantity & y)
|
||||
{
|
||||
return (Quantity(x, u::dimensionless) == y);
|
||||
}
|
||||
|
||||
/** note: won't have constexpr result until c++26 (when ::sqrt(), ::pow() are constexpr)
|
||||
**/
|
||||
template <typename Quantity, double>
|
||||
requires quantity_concept<Quantity>
|
||||
constexpr auto
|
||||
operator<=> (const Quantity & x, double y)
|
||||
{
|
||||
return Quantity::compare(x, Quantity(y, u::dimensionless));
|
||||
}
|
||||
|
||||
/** note: won't have constexpr result until c++26 (when ::sqrt(), ::pow() are constexpr)
|
||||
**/
|
||||
template <typename Quantity, double>
|
||||
requires quantity_concept<Quantity>
|
||||
constexpr auto
|
||||
operator<=> (double x, const Quantity & y)
|
||||
{
|
||||
return Quantity::compare(Quantity(x, u::dimensionless), y);
|
||||
}
|
||||
|
||||
namespace xu {
|
||||
constexpr auto nanogram = xquantity(1.0, u::nanogram);
|
||||
}
|
||||
} /*namespace qty*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/** end xquantity.hpp **/
|
||||
27
xo-unit/include/xo/unit/xquantity_iostream.hpp
Normal file
27
xo-unit/include/xo/unit/xquantity_iostream.hpp
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/** @file xquantity_iostream.hpp
|
||||
*
|
||||
* Author: Roland Conybeare
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "xquantity.hpp"
|
||||
#include "natural_unit_iostream.hpp"
|
||||
//#include <iostream>
|
||||
|
||||
namespace xo {
|
||||
namespace qty {
|
||||
template <typename Repr = double,
|
||||
typename Int = std::int64_t>
|
||||
inline std::ostream &
|
||||
operator<< (std::ostream & os,
|
||||
const xquantity<Repr, Int> & x)
|
||||
{
|
||||
os << x.scale() << x.abbrev();
|
||||
|
||||
return os;
|
||||
}
|
||||
} /*namespace qty*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/** end xquantity_iostream.hpp **/
|
||||
38
xo-unit/pkgs/xo-cmake.nix
Normal file
38
xo-unit/pkgs/xo-cmake.nix
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
# dependencies
|
||||
stdenv, cmake, # ... other deps here
|
||||
|
||||
# args
|
||||
|
||||
# attrset for fetching source code.
|
||||
# { type, owner, repo, ref }
|
||||
#
|
||||
# e.g. type="github", owner="rconybea", repo="cmake-examples", ref="ex1b"
|
||||
#
|
||||
# see [[../flake.nix]]
|
||||
#
|
||||
#cmake-examples-ex1-path
|
||||
|
||||
# someconfigurationoption ? false
|
||||
} :
|
||||
|
||||
stdenv.mkDerivation (finalattrs:
|
||||
{
|
||||
name = "xo-cmake";
|
||||
|
||||
# src = cmake-examples-ex1-path;
|
||||
|
||||
src = (fetchGit {
|
||||
url = "https://github.com/rconybea/xo-cmake";
|
||||
version = "1.0";
|
||||
#ref = "ex1";
|
||||
#rev = "c0472c9d7e4d2c53bfb977d3182380832fe96645";
|
||||
});
|
||||
|
||||
nativeBuildInputs = [ cmake ];
|
||||
|
||||
# installPhase = ''
|
||||
# mkdir -p $out
|
||||
# echo 'This project intentionally has no install phase'
|
||||
# '';
|
||||
})
|
||||
75
xo-unit/pkgs/xo-flatstring.nix
Normal file
75
xo-unit/pkgs/xo-flatstring.nix
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
{
|
||||
# 1. nixpkgs dependencies
|
||||
# 1.1. python
|
||||
python, pythonPackages,
|
||||
|
||||
# 1.2. particular python packages
|
||||
sphinx ? pythonPackages.sphinx,
|
||||
sphinx-rtd-theme ? pythonPackages.sphinx-rtd-theme,
|
||||
breathe ? pythonPackages.breathe,
|
||||
|
||||
# 1.3. document-generation packages
|
||||
# use of makeFontsConf adapted from nixpkgs/development/libraries/gtkmm/4.x.nix
|
||||
#
|
||||
doxygen, graphviz,
|
||||
##fontconfig,
|
||||
##makeFontsConf,
|
||||
|
||||
# 1.4. c++ build/utest chain
|
||||
stdenv, cmake, catch2, # ... other deps here
|
||||
|
||||
# 2. xo dependencies
|
||||
xo-cmake, xo-indentlog
|
||||
|
||||
# args
|
||||
|
||||
# attrset for fetching source code.
|
||||
# { type, owner, repo, ref }
|
||||
#
|
||||
# e.g. type="github", owner="rconybea", repo="cmake-examples", ref="ex1b"
|
||||
#
|
||||
# see [[../flake.nix]]
|
||||
#
|
||||
#cmake-examples-ex1-path
|
||||
|
||||
# someconfigurationoption ? false
|
||||
} :
|
||||
|
||||
stdenv.mkDerivation (finalattrs:
|
||||
{
|
||||
name = "xo-flatstring";
|
||||
|
||||
src = (fetchGit {
|
||||
url = "https://github.com/rconybea/xo-flatstring";
|
||||
version = "1.0";
|
||||
#ref = "ex1";
|
||||
#rev = "c0472c9d7e4d2c53bfb977d3182380832fe96645";
|
||||
});
|
||||
|
||||
cmakeFlags = ["-DXO_CMAKE_CONFIG_EXECUTABLE=${xo-cmake}/bin/xo-cmake-config"];
|
||||
|
||||
# move HOME so fontconfig can do sensible things
|
||||
buildPhase = ''
|
||||
#set -x
|
||||
|
||||
echo "FONTCONFIG_FILE=$FONTCONFIG_FILE"
|
||||
|
||||
#export FONTCONFIG_FILE=$fontconfig.out/etc/fonts/fonts.conf
|
||||
export HOME=$TMPDIR
|
||||
export XDG_CONFIG_HOME=$TMPDIR
|
||||
|
||||
mkdir $XDG_CONFIG_HOME/fontconfig
|
||||
|
||||
#grep xdg $FONTCONFIG_FILE
|
||||
|
||||
#$fontconfig.out/bin/fc-cache -v
|
||||
|
||||
make && make docs
|
||||
#make
|
||||
'';
|
||||
|
||||
doCheck = true;
|
||||
nativeBuildInputs = [ cmake catch2
|
||||
doxygen graphviz sphinx sphinx-rtd-theme breathe ];
|
||||
propagatedBuildInputs = [ xo-indentlog ];
|
||||
})
|
||||
36
xo-unit/pkgs/xo-indentlog.nix
Normal file
36
xo-unit/pkgs/xo-indentlog.nix
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
# nixpkgs dependencies
|
||||
stdenv, cmake, catch2, # ... other deps here
|
||||
|
||||
# xo dependencies
|
||||
xo-cmake,
|
||||
|
||||
# args
|
||||
|
||||
# attrset for fetching source code.
|
||||
# { type, owner, repo, ref }
|
||||
#
|
||||
# e.g. type="github", owner="rconybea", repo="cmake-examples", ref="ex1b"
|
||||
#
|
||||
# see [[../flake.nix]]
|
||||
#
|
||||
#cmake-examples-ex1-path
|
||||
|
||||
# someconfigurationoption ? false
|
||||
} :
|
||||
|
||||
stdenv.mkDerivation (finalattrs:
|
||||
{
|
||||
name = "xo-indentlog";
|
||||
|
||||
src = (fetchGit {
|
||||
url = "https://github.com/rconybea/indentlog";
|
||||
version = "1.0";
|
||||
#ref = "ex1";
|
||||
#rev = "c0472c9d7e4d2c53bfb977d3182380832fe96645";
|
||||
});
|
||||
|
||||
cmakeFlags = ["-DXO_CMAKE_CONFIG_EXECUTABLE=${xo-cmake}/bin/xo-cmake-config"];
|
||||
doCheck = true;
|
||||
nativeBuildInputs = [ cmake catch2 ];
|
||||
})
|
||||
37
xo-unit/pkgs/xo-randomgen.nix
Normal file
37
xo-unit/pkgs/xo-randomgen.nix
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
# nixpkgs dependencies
|
||||
stdenv, cmake, catch2, # ... other deps here
|
||||
|
||||
# xo dependencies
|
||||
xo-cmake, xo-indentlog
|
||||
|
||||
# args
|
||||
|
||||
# attrset for fetching source code.
|
||||
# { type, owner, repo, ref }
|
||||
#
|
||||
# e.g. type="github", owner="rconybea", repo="cmake-examples", ref="ex1b"
|
||||
#
|
||||
# see [[../flake.nix]]
|
||||
#
|
||||
#cmake-examples-ex1-path
|
||||
|
||||
# someconfigurationoption ? false
|
||||
} :
|
||||
|
||||
stdenv.mkDerivation (finalattrs:
|
||||
{
|
||||
name = "xo-randomgen";
|
||||
|
||||
src = (fetchGit {
|
||||
url = "https://github.com/rconybea/randomgen";
|
||||
version = "1.0";
|
||||
#ref = "ex1";
|
||||
#rev = "c0472c9d7e4d2c53bfb977d3182380832fe96645";
|
||||
});
|
||||
|
||||
cmakeFlags = ["-DXO_CMAKE_CONFIG_EXECUTABLE=${xo-cmake}/bin/xo-cmake-config"];
|
||||
doCheck = true;
|
||||
nativeBuildInputs = [ cmake catch2 ];
|
||||
propagatedBuildInputs = [ xo-indentlog ];
|
||||
})
|
||||
83
xo-unit/pkgs/xo-ratio.nix
Normal file
83
xo-unit/pkgs/xo-ratio.nix
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
{
|
||||
# 1. nixpkgs dependencies
|
||||
# 1.1. python
|
||||
python, pythonPackages,
|
||||
|
||||
# 1.2. particular python packages
|
||||
sphinx ? pythonPackages.sphinx,
|
||||
sphinx-rtd-theme ? pythonPackages.sphinx-rtd-theme,
|
||||
breathe ? pythonPackages.breathe,
|
||||
|
||||
# 1.3. document-generation packages
|
||||
# use of makeFontsConf adapted from nixpkgs/development/libraries/gtkmm/4.x.nix
|
||||
#
|
||||
doxygen, graphviz,
|
||||
##fontconfig,
|
||||
##makeFontsConf,
|
||||
|
||||
# used for graphviz (dot) see docs/Doxyfile.in
|
||||
#helvetica-neue-lt-std,
|
||||
|
||||
# 1.4. c++ build/utest chain
|
||||
stdenv, cmake, catch2, # ... other deps here
|
||||
|
||||
# 2. xo dependencies
|
||||
xo-cmake, xo-flatstring, xo-randomgen,
|
||||
|
||||
# args
|
||||
|
||||
# attrset for fetching source code.
|
||||
# { type, owner, repo, ref }
|
||||
#
|
||||
# e.g. type="github", owner="rconybea", repo="cmake-examples", ref="ex1b"
|
||||
#
|
||||
# see [[../flake.nix]]
|
||||
#
|
||||
#cmake-examples-ex1-path
|
||||
|
||||
# someconfigurationoption ? false
|
||||
} :
|
||||
|
||||
stdenv.mkDerivation (finalattrs:
|
||||
{
|
||||
name = "xo-ratio";
|
||||
|
||||
src = (fetchGit {
|
||||
url = "https://github.com/rconybea/xo-ratio";
|
||||
version = "1.0";
|
||||
#ref = "ex1";
|
||||
#rev = "c0472c9d7e4d2c53bfb977d3182380832fe96645";
|
||||
});
|
||||
|
||||
cmakeFlags = ["-DXO_CMAKE_CONFIG_EXECUTABLE=${xo-cmake}/bin/xo-cmake-config"];
|
||||
|
||||
# NOTE: helvetic-neue-lt-std has unfree license
|
||||
#FONTCONFIG_FILE = makeFontsConf { fontDirectories = [ helvetica-neue-lt-std ]; };
|
||||
|
||||
# move HOME so fontconfig can do sensible things
|
||||
buildPhase = ''
|
||||
#set -x
|
||||
|
||||
echo "FONTCONFIG_FILE=$FONTCONFIG_FILE"
|
||||
|
||||
#export FONTCONFIG_FILE=$fontconfig.out/etc/fonts/fonts.conf
|
||||
export HOME=$TMPDIR
|
||||
export XDG_CONFIG_HOME=$TMPDIR
|
||||
|
||||
mkdir $XDG_CONFIG_HOME/fontconfig
|
||||
|
||||
#grep xdg $FONTCONFIG_FILE
|
||||
|
||||
#$fontconfig.out/bin/fc-cache -v
|
||||
|
||||
make && make docs
|
||||
#make
|
||||
'';
|
||||
|
||||
doCheck = true;
|
||||
nativeBuildInputs = [ cmake catch2
|
||||
doxygen graphviz sphinx sphinx-rtd-theme breathe
|
||||
xo-randomgen
|
||||
];
|
||||
propagatedBuildInputs = [ xo-flatstring ];
|
||||
})
|
||||
37
xo-unit/pkgs/xo-refcnt.nix
Normal file
37
xo-unit/pkgs/xo-refcnt.nix
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
# nixpkgs dependencies
|
||||
stdenv, cmake, catch2, # ... other deps here
|
||||
|
||||
# xo dependencies
|
||||
xo-cmake, xo-indentlog
|
||||
|
||||
# args
|
||||
|
||||
# attrset for fetching source code.
|
||||
# { type, owner, repo, ref }
|
||||
#
|
||||
# e.g. type="github", owner="rconybea", repo="cmake-examples", ref="ex1b"
|
||||
#
|
||||
# see [[../flake.nix]]
|
||||
#
|
||||
#cmake-examples-ex1-path
|
||||
|
||||
# someconfigurationoption ? false
|
||||
} :
|
||||
|
||||
stdenv.mkDerivation (finalattrs:
|
||||
{
|
||||
name = "xo-refcnt";
|
||||
|
||||
src = (fetchGit {
|
||||
url = "https://github.com/rconybea/refcnt";
|
||||
version = "1.0";
|
||||
#ref = "ex1";
|
||||
#rev = "c0472c9d7e4d2c53bfb977d3182380832fe96645";
|
||||
});
|
||||
|
||||
cmakeFlags = ["-DXO_CMAKE_CONFIG_EXECUTABLE=${xo-cmake}/bin/xo-cmake-config"];
|
||||
doCheck = true;
|
||||
nativeBuildInputs = [ cmake catch2 ];
|
||||
propagatedBuildInputs = [ xo-indentlog ];
|
||||
})
|
||||
37
xo-unit/pkgs/xo-reflect.nix
Normal file
37
xo-unit/pkgs/xo-reflect.nix
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
# nixpkgs dependencies
|
||||
stdenv, cmake, catch2, # ... other deps here
|
||||
|
||||
# xo dependencies
|
||||
xo-cmake, xo-refcnt, xo-subsys,
|
||||
|
||||
# args
|
||||
|
||||
# attrset for fetching source code.
|
||||
# { type, owner, repo, ref }
|
||||
#
|
||||
# e.g. type="github", owner="rconybea", repo="cmake-examples", ref="ex1b"
|
||||
#
|
||||
# see [[../flake.nix]]
|
||||
#
|
||||
#cmake-examples-ex1-path
|
||||
|
||||
# someconfigurationoption ? false
|
||||
} :
|
||||
|
||||
stdenv.mkDerivation (finalattrs:
|
||||
{
|
||||
name = "xo-reflect";
|
||||
|
||||
src = (fetchGit {
|
||||
url = "https://github.com/rconybea/reflect";
|
||||
version = "1.0";
|
||||
#ref = "ex1";
|
||||
#rev = "c0472c9d7e4d2c53bfb977d3182380832fe96645";
|
||||
});
|
||||
|
||||
cmakeFlags = ["-DXO_CMAKE_CONFIG_EXECUTABLE=${xo-cmake}/bin/xo-cmake-config"];
|
||||
doCheck = true;
|
||||
nativeBuildInputs = [ cmake catch2 ];
|
||||
propagatedBuildInputs = [ xo-subsys xo-refcnt ];
|
||||
})
|
||||
36
xo-unit/pkgs/xo-subsys.nix
Normal file
36
xo-unit/pkgs/xo-subsys.nix
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
# nixpkgs dependencies
|
||||
stdenv, cmake, catch2, # ... other deps here
|
||||
|
||||
# xo dependencies
|
||||
xo-cmake,
|
||||
|
||||
# args
|
||||
|
||||
# attrset for fetching source code.
|
||||
# { type, owner, repo, ref }
|
||||
#
|
||||
# e.g. type="github", owner="rconybea", repo="cmake-examples", ref="ex1b"
|
||||
#
|
||||
# see [[../flake.nix]]
|
||||
#
|
||||
#cmake-examples-ex1-path
|
||||
|
||||
# someconfigurationoption ? false
|
||||
} :
|
||||
|
||||
stdenv.mkDerivation (finalattrs:
|
||||
{
|
||||
name = "xo-subsys";
|
||||
|
||||
src = (fetchGit {
|
||||
url = "https://github.com/rconybea/subsys";
|
||||
version = "1.0";
|
||||
#ref = "ex1";
|
||||
#rev = "c0472c9d7e4d2c53bfb977d3182380832fe96645";
|
||||
});
|
||||
|
||||
cmakeFlags = ["-DXO_CMAKE_CONFIG_EXECUTABLE=${xo-cmake}/bin/xo-cmake-config"];
|
||||
#doCheck = true;
|
||||
nativeBuildInputs = [ cmake catch2 ];
|
||||
})
|
||||
79
xo-unit/pkgs/xo-unit.nix
Normal file
79
xo-unit/pkgs/xo-unit.nix
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
{
|
||||
# 1. nixpkgs dependencies
|
||||
# 1.1. python
|
||||
python, pythonPackages,
|
||||
|
||||
# 1.2. particular python packages
|
||||
sphinx ? pythonPackages.sphinx,
|
||||
sphinx-rtd-theme ? pythonPackages.sphinx-rtd-theme,
|
||||
breathe ? pythonPackages.breathe,
|
||||
|
||||
# 1.3. document-generation packages
|
||||
# use of makeFontsConf adapted from nixpkgs/development/libraries/gtkmm/4.x.nix
|
||||
#
|
||||
doxygen, graphviz,
|
||||
#fontconfig,
|
||||
makeFontsConf,
|
||||
|
||||
# used for graphviz (dot) see docs/Doxyfile.in
|
||||
#helvetica-neue-lt-std,
|
||||
|
||||
# 1.4. c++ build/utest chain
|
||||
stdenv, cmake, catch2, # ... other deps here
|
||||
|
||||
# 2. xo dependencies
|
||||
xo-cmake, xo-flatstring, xo-ratio, xo-randomgen,
|
||||
|
||||
# args
|
||||
|
||||
# attrset for fetching source code.
|
||||
# { type, owner, repo, ref }
|
||||
#
|
||||
# e.g. type="github", owner="rconybea", repo="cmake-examples", ref="ex1b"
|
||||
#
|
||||
# see [[../flake.nix]]
|
||||
#
|
||||
#cmake-examples-ex1-path
|
||||
|
||||
# someconfigurationoption ? false
|
||||
} :
|
||||
|
||||
stdenv.mkDerivation (finalattrs:
|
||||
{
|
||||
name = "xo-unit";
|
||||
|
||||
src = (fetchGit {
|
||||
url = "https://github.com/rconybea/xo-unit";
|
||||
version = "1.0";
|
||||
#ref = "ex1";
|
||||
#rev = "c0472c9d7e4d2c53bfb977d3182380832fe96645";
|
||||
});
|
||||
|
||||
cmakeFlags = ["-DXO_CMAKE_CONFIG_EXECUTABLE=${xo-cmake}/bin/xo-cmake-config"];
|
||||
|
||||
# NOTE: helvetic-neue-lt-std has unfree license
|
||||
#FONTCONFIG_FILE = makeFontsConf { fontDirectories = [ helvetica-neue-lt-std ]; };
|
||||
|
||||
# move HOME so fontconfig can do sensible things
|
||||
buildPhase = ''
|
||||
set -x
|
||||
|
||||
echo "FONTCONFIG_FILE=$FONTCONFIG_FILE"
|
||||
|
||||
#export FONTCONFIG_FILE=$fontconfig.out/etc/fonts/fonts.conf
|
||||
export HOME=$TMPDIR
|
||||
export XDG_CONFIG_HOME=$TMPDIR
|
||||
|
||||
mkdir $XDG_CONFIG_HOME/fontconfig
|
||||
|
||||
#grep xdg $FONTCONFIG_FILE
|
||||
|
||||
#$fontconfig.out/bin/fc-cache -v
|
||||
|
||||
make && make docs
|
||||
'';
|
||||
|
||||
doCheck = true;
|
||||
nativeBuildInputs = [ cmake catch2 doxygen graphviz sphinx sphinx-rtd-theme breathe xo-randomgen ];
|
||||
propagatedBuildInputs = [ xo-flatstring xo-ratio ];
|
||||
})
|
||||
27
xo-unit/pkgs/xo-userenv.nix
Normal file
27
xo-unit/pkgs/xo-userenv.nix
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
# nixpkgs dependencies
|
||||
buildFHSUserEnv, # ... other deps here
|
||||
|
||||
# xo dependencies
|
||||
xo-cmake, xo-indentlog, xo-flatstring, xo-subsys, xo-refcnt, xo-ratio, xo-reflect, xo-randomgen, xo-unit,
|
||||
|
||||
# other args
|
||||
|
||||
# someconfigurationoption ? false
|
||||
} :
|
||||
|
||||
buildFHSUserEnv {
|
||||
name = "xo-userenv";
|
||||
targetPkgs = pkgs: [ xo-cmake
|
||||
xo-indentlog
|
||||
xo-flatstring
|
||||
xo-subsys
|
||||
xo-refcnt
|
||||
xo-ratio
|
||||
xo-reflect
|
||||
xo-randomgen
|
||||
xo-unit
|
||||
];
|
||||
# runScript = ...;
|
||||
# profile = ...;
|
||||
}
|
||||
26
xo-unit/utest/CMakeLists.txt
Normal file
26
xo-unit/utest/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# xo-unit/utest/CMakeLists.txt
|
||||
|
||||
set(SELF_EXE utest.unit)
|
||||
set(SELF_SRCS
|
||||
unit_utest_main.cpp #mpl_unit.test.cpp
|
||||
xquantity.test.cpp
|
||||
quantity.test.cpp
|
||||
bpu.test.cpp
|
||||
basis_unit.test.cpp
|
||||
scaled_unit.test.cpp
|
||||
natural_unit.test.cpp
|
||||
unit.test.cpp #quantity.test.cpp
|
||||
)
|
||||
|
||||
if (ENABLE_TESTING)
|
||||
xo_add_utest_executable(${SELF_EXE} ${SELF_SRCS})
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
# dependencies..
|
||||
|
||||
xo_self_dependency(${SELF_EXE} xo_unit)
|
||||
xo_headeronly_dependency(${SELF_EXE} xo_ratio)
|
||||
xo_external_target_dependency(${SELF_EXE} Catch2 Catch2::Catch2)
|
||||
endif()
|
||||
|
||||
# end CMakeLists.txt
|
||||
153
xo-unit/utest/basis_unit.test.cpp
Normal file
153
xo-unit/utest/basis_unit.test.cpp
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
/* @file bu.test.cpp */
|
||||
|
||||
#include "xo/unit/basis_unit.hpp"
|
||||
#include "xo/unit/bu_store.hpp"
|
||||
#include "xo/indentlog/scope.hpp"
|
||||
//#include "xo/indentlog/print/tag.hpp"
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
namespace xo {
|
||||
using xo::qty::scalefactor_ratio_type;
|
||||
using xo::qty::bu_abbrev;
|
||||
using xo::qty::basis_unit;
|
||||
using xo::qty::bu_abbrev_type;
|
||||
using xo::qty::native_unit2_v;
|
||||
using xo::qty::dim;
|
||||
namespace bu = xo::qty::detail::bu;
|
||||
|
||||
namespace ut {
|
||||
|
||||
/* compile-time test:
|
||||
* verify we can use a basis_unit as a non-type template parameter
|
||||
* we will need this for quantity<Repr, Int, natural_unit<Int>>
|
||||
*/
|
||||
template <basis_unit bu>
|
||||
constexpr bu_abbrev_type bu_mpl_abbrev = bu_abbrev(bu);
|
||||
|
||||
TEST_CASE("basis_unit", "[basis_unit]") {
|
||||
static_assert(bu_mpl_abbrev<bu::gram> == bu_abbrev(bu::gram));
|
||||
REQUIRE(bu_mpl_abbrev<bu::gram> == bu_abbrev(bu::gram));
|
||||
} /*TEST_CASE(basis_unit)*/
|
||||
|
||||
TEST_CASE("basis_unit1", "[basis_unit]") {
|
||||
constexpr bool c_debug_flag = false;
|
||||
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.basis_unit1"));
|
||||
|
||||
static_assert(native_unit2_v[static_cast<int>(dim::mass)].native_dim() == dim::mass);
|
||||
static_assert(native_unit2_v[static_cast<int>(dim::distance)].native_dim() == dim::distance);
|
||||
static_assert(native_unit2_v[static_cast<int>(dim::time)].native_dim() == dim::time);
|
||||
static_assert(native_unit2_v[static_cast<int>(dim::time)].native_dim() == dim::time);
|
||||
static_assert(native_unit2_v[static_cast<int>(dim::currency)].native_dim() == dim::currency);
|
||||
static_assert(native_unit2_v[static_cast<int>(dim::price)].native_dim() == dim::price);
|
||||
|
||||
log && log(xtag("mass*10^3", bu_abbrev(bu::kilogram)));
|
||||
|
||||
static_assert(bu_abbrev(bu::kilogram)
|
||||
== bu_abbrev_type::from_chars("kg"));
|
||||
|
||||
log && log("---------------------");
|
||||
|
||||
/* note: using CHECK to make test show up in coverage */
|
||||
|
||||
# define REQUIRE_x2(x) static_assert(x); REQUIRE(x)
|
||||
|
||||
log && log(xtag("mass", bu_abbrev(bu::meter)));
|
||||
|
||||
REQUIRE_x2(bu_abbrev(bu::picogram) == bu_abbrev_type::from_chars("pg"));
|
||||
REQUIRE_x2(bu_abbrev(bu::nanogram)
|
||||
== bu_abbrev_type::from_chars("ng"));
|
||||
REQUIRE_x2(bu_abbrev(bu::microgram)
|
||||
== bu_abbrev_type::from_chars("ug"));
|
||||
REQUIRE_x2(bu_abbrev(bu::milligram)
|
||||
== bu_abbrev_type::from_chars("mg"));
|
||||
REQUIRE_x2(bu_abbrev(bu::gram)
|
||||
== bu_abbrev_type::from_chars("g"));
|
||||
REQUIRE_x2(bu_abbrev(bu::kilogram)
|
||||
== bu_abbrev_type::from_chars("kg"));
|
||||
REQUIRE_x2(bu_abbrev(bu::tonne)
|
||||
== bu_abbrev_type::from_chars("t"));
|
||||
REQUIRE_x2(bu_abbrev(bu::kilotonne)
|
||||
== bu_abbrev_type::from_chars("kt"));
|
||||
REQUIRE_x2(bu_abbrev(bu::megatonne)
|
||||
== bu_abbrev_type::from_chars("Mt"));
|
||||
REQUIRE_x2(bu_abbrev(bu::gigatonne)
|
||||
== bu_abbrev_type::from_chars("Gt"));
|
||||
|
||||
log && log(xtag("distance", bu_abbrev(bu::meter)));
|
||||
|
||||
REQUIRE_x2(bu_abbrev(bu::picometre)
|
||||
== bu_abbrev_type::from_chars("pm"));
|
||||
REQUIRE_x2(bu_abbrev(bu::nanometre)
|
||||
== bu_abbrev_type::from_chars("nm"));
|
||||
REQUIRE_x2(bu_abbrev(bu::micrometre)
|
||||
== bu_abbrev_type::from_chars("um"));
|
||||
REQUIRE_x2(bu_abbrev(bu::millimetre)
|
||||
== bu_abbrev_type::from_chars("mm"));
|
||||
REQUIRE_x2(bu_abbrev(bu::metre)
|
||||
== bu_abbrev_type::from_chars("m"));
|
||||
REQUIRE_x2(bu_abbrev(bu::kilometre)
|
||||
== bu_abbrev_type::from_chars("km"));
|
||||
REQUIRE_x2(bu_abbrev(bu::megametre)
|
||||
== bu_abbrev_type::from_chars("Mm"));
|
||||
REQUIRE_x2(bu_abbrev(bu::gigametre)
|
||||
== bu_abbrev_type::from_chars("Gm"));
|
||||
|
||||
REQUIRE_x2(bu_abbrev(bu::picometer)
|
||||
== bu_abbrev_type::from_chars("pm"));
|
||||
REQUIRE_x2(bu_abbrev(bu::nanometer)
|
||||
== bu_abbrev_type::from_chars("nm"));
|
||||
REQUIRE_x2(bu_abbrev(bu::micrometer)
|
||||
== bu_abbrev_type::from_chars("um"));
|
||||
REQUIRE_x2(bu_abbrev(bu::millimeter)
|
||||
== bu_abbrev_type::from_chars("mm"));
|
||||
REQUIRE_x2(bu_abbrev(bu::meter)
|
||||
== bu_abbrev_type::from_chars("m"));
|
||||
REQUIRE_x2(bu_abbrev(bu::kilometer)
|
||||
== bu_abbrev_type::from_chars("km"));
|
||||
REQUIRE_x2(bu_abbrev(bu::megameter)
|
||||
== bu_abbrev_type::from_chars("Mm"));
|
||||
REQUIRE_x2(bu_abbrev(bu::gigameter)
|
||||
== bu_abbrev_type::from_chars("Gm"));
|
||||
|
||||
REQUIRE_x2(bu_abbrev(bu::lightsecond) == flatstring("lsec"));
|
||||
REQUIRE_x2(bu_abbrev(bu::astronomicalunit) == flatstring("AU"));
|
||||
|
||||
REQUIRE_x2(bu_abbrev(bu::inch) == flatstring("in"));
|
||||
REQUIRE_x2(bu_abbrev(bu::foot) == flatstring("ft"));
|
||||
REQUIRE_x2(bu_abbrev(bu::yard) == flatstring("yd"));
|
||||
REQUIRE_x2(bu_abbrev(bu::mile) == flatstring("mi"));
|
||||
|
||||
log && log(xtag("time", bu_abbrev(bu::second)));
|
||||
|
||||
REQUIRE_x2(bu_abbrev(bu::picosecond) == bu_abbrev_type::from_chars("ps"));
|
||||
REQUIRE_x2(bu_abbrev(bu::nanosecond) == bu_abbrev_type::from_chars("ns"));
|
||||
REQUIRE_x2(bu_abbrev(bu::microsecond) == bu_abbrev_type::from_chars("us"));
|
||||
REQUIRE_x2(bu_abbrev(bu::millisecond) == bu_abbrev_type::from_chars("ms"));
|
||||
REQUIRE_x2(bu_abbrev(bu::second) == bu_abbrev_type::from_chars("s"));
|
||||
REQUIRE_x2(bu_abbrev(bu::minute) == bu_abbrev_type::from_chars("min"));
|
||||
REQUIRE_x2(bu_abbrev(bu::hour) == bu_abbrev_type::from_chars("hr"));
|
||||
REQUIRE_x2(bu_abbrev(bu::day) == bu_abbrev_type::from_chars("dy"));
|
||||
REQUIRE_x2(bu_abbrev(bu::week) == bu_abbrev_type::from_chars("wk"));
|
||||
REQUIRE_x2(bu_abbrev(bu::month) == bu_abbrev_type::from_chars("mo"));
|
||||
|
||||
REQUIRE_x2(bu_abbrev(bu::year) == bu_abbrev_type::from_chars("yr"));
|
||||
REQUIRE_x2(bu_abbrev(bu::year250) == bu_abbrev_type::from_chars("yr250"));
|
||||
REQUIRE_x2(bu_abbrev(bu::year360) == bu_abbrev_type::from_chars("yr360"));
|
||||
REQUIRE_x2(bu_abbrev(bu::year365) == bu_abbrev_type::from_chars("yr365"));
|
||||
|
||||
log && log(xtag("currency", bu_abbrev(bu::currency)));
|
||||
|
||||
REQUIRE_x2(bu_abbrev(bu::currency) == flatstring("ccy"));
|
||||
|
||||
log && log(xtag("price", bu_abbrev(bu::price)));
|
||||
|
||||
REQUIRE_x2(bu_abbrev(bu::price) == flatstring("px"));
|
||||
|
||||
# undef REQUIRE_x2
|
||||
|
||||
} /*TEST_CASE(basis_unit1)*/
|
||||
|
||||
} /*namespace ut*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end bu.test.cpp */
|
||||
95
xo-unit/utest/bpu.test.cpp
Normal file
95
xo-unit/utest/bpu.test.cpp
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/* @file bpu.test.cpp */
|
||||
|
||||
#include "xo/unit/bpu.hpp"
|
||||
#include "xo/indentlog/scope.hpp"
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
namespace xo {
|
||||
using xo::qty::abbrev::bpu_abbrev;
|
||||
using xo::qty::abbrev::flatstring_from_exponent;
|
||||
|
||||
namespace qty {
|
||||
using bpu64_type = bpu<std::int64_t>;
|
||||
|
||||
/* compile-time test:
|
||||
* verify we can use a bpu64_type instance as a non-type template parameter.
|
||||
* Will need this for quantity<Repr, Int, natural_unit<Int>>
|
||||
*/
|
||||
template <bpu64_type bpu>
|
||||
constexpr bpu_abbrev_type bpu_mpl_abbrev = bpu.abbrev();
|
||||
|
||||
TEST_CASE("bpu", "[bpu]") {
|
||||
static_assert(bpu_mpl_abbrev<bpu64_type::unit_power(detail::bu::gram)>
|
||||
== bpu64_type::unit_power(detail::bu::gram).abbrev());
|
||||
REQUIRE(bpu_mpl_abbrev<bpu64_type::unit_power(detail::bu::gram)>
|
||||
== bpu64_type::unit_power(detail::bu::gram).abbrev());
|
||||
} /*TEST_CASE(bpu)*/
|
||||
|
||||
TEST_CASE("flatstring_from_exponent", "[flatstring_from_exponent]") {
|
||||
constexpr bool c_debug_flag = false;
|
||||
|
||||
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.flatstring_from_exponent"));
|
||||
|
||||
log && log(xtag("^-3", flatstring_from_exponent(power_ratio_type(-3,1))));
|
||||
log && log(xtag("^-2", flatstring_from_exponent(power_ratio_type(-2,1))));
|
||||
log && log(xtag("^-1", flatstring_from_exponent(power_ratio_type(-1,1))));
|
||||
log && log(xtag("^-1/2", flatstring_from_exponent(power_ratio_type(-1,2))));
|
||||
log && log(xtag("^0", flatstring_from_exponent(power_ratio_type(0,1))));
|
||||
log && log(xtag("^1/2", flatstring_from_exponent(power_ratio_type(1,2))));
|
||||
log && log(xtag("^1", flatstring_from_exponent(power_ratio_type(1,1))));
|
||||
log && log(xtag("^2", flatstring_from_exponent(power_ratio_type(2,1))));
|
||||
log && log(xtag("^3", flatstring_from_exponent(power_ratio_type(3,1))));
|
||||
|
||||
static_assert(flatstring<5>::from_flatstring(flatstring_from_exponent(power_ratio_type(-3,1)))
|
||||
== flatstring<5>::from_flatstring(flatstring("^-3")));
|
||||
static_assert(flatstring<5>::from_flatstring(flatstring_from_exponent(power_ratio_type(-2,1)))
|
||||
== flatstring<5>::from_flatstring(flatstring("^-2")));
|
||||
static_assert(flatstring<5>::from_flatstring(flatstring_from_exponent(power_ratio_type(-1,1)))
|
||||
== flatstring<5>::from_flatstring(flatstring("^-1")));
|
||||
static_assert(flatstring<5>::from_flatstring(flatstring_from_exponent(power_ratio_type(-1,2)))
|
||||
== flatstring<5>::from_flatstring(flatstring("^(-1/2)")));
|
||||
static_assert(flatstring<5>::from_flatstring(flatstring_from_exponent(power_ratio_type(1,2)))
|
||||
== flatstring<5>::from_flatstring(flatstring("^(1/2)")));
|
||||
static_assert(flatstring<5>::from_flatstring(flatstring_from_exponent(power_ratio_type(1,1)))
|
||||
== flatstring<5>::from_flatstring(flatstring("")));
|
||||
static_assert(flatstring<5>::from_flatstring(flatstring_from_exponent(power_ratio_type(2,1)))
|
||||
== flatstring<5>::from_flatstring(flatstring("^2")));
|
||||
static_assert(flatstring<5>::from_flatstring(flatstring_from_exponent(power_ratio_type(3,1)))
|
||||
== flatstring<5>::from_flatstring(flatstring("^3")));
|
||||
} /*TEST_CASE(flatstring_from_exponent)*/
|
||||
|
||||
TEST_CASE("bpu_abbrev", "[bpu_abbrev]") {
|
||||
constexpr bool c_debug_flag = false;
|
||||
|
||||
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.bpu2_assemble_abbrev"));
|
||||
|
||||
log && log(xtag("1/(kg*kg)", bpu_abbrev(dim::mass, scalefactor_ratio_type(1000, 1), power_ratio_type(-2, 1))));
|
||||
log && log(xtag("1/kg", bpu_abbrev(dim::mass, scalefactor_ratio_type(1000, 1), power_ratio_type(-1, 1))));
|
||||
log && log(xtag("kg", bpu_abbrev(dim::mass, scalefactor_ratio_type(1000, 1), power_ratio_type(1, 1))));
|
||||
log && log(xtag("kg*kg", bpu_abbrev(dim::mass, scalefactor_ratio_type(1000, 1), power_ratio_type(2, 1))));
|
||||
|
||||
static_assert(bpu<int64_t>(dim::mass, scalefactor_ratio_type(1, 1), power_ratio_type(1, 1)).abbrev()
|
||||
== bpu_abbrev_type::from_chars("g"));
|
||||
static_assert(bpu<int64_t>(dim::mass, scalefactor_ratio_type(1000, 1), power_ratio_type(1, 1)).abbrev()
|
||||
== bpu_abbrev_type::from_chars("kg"));
|
||||
static_assert(bpu<int64_t>(dim::mass, scalefactor_ratio_type(1000, 1), power_ratio_type(-1, 1)).abbrev()
|
||||
== bpu_abbrev_type::from_chars("kg^-1"));
|
||||
static_assert(bpu<int64_t>(dim::mass, scalefactor_ratio_type(1000, 1), power_ratio_type(-2, 1)).abbrev()
|
||||
== bpu_abbrev_type::from_chars("kg^-2"));
|
||||
|
||||
static_assert(bpu<int64_t>(dim::time, scalefactor_ratio_type(60, 1), power_ratio_type(-2, 1)).abbrev()
|
||||
== bpu_abbrev_type::from_chars("min^-2"));
|
||||
static_assert(bpu<int64_t>(dim::time, scalefactor_ratio_type(3600, 1), power_ratio_type(-1, 1)).abbrev()
|
||||
== bpu_abbrev_type::from_chars("hr^-1"));
|
||||
static_assert(bpu<int64_t>(dim::time, scalefactor_ratio_type(24*3600, 1), power_ratio_type(-1, 1)).abbrev()
|
||||
== bpu_abbrev_type::from_chars("dy^-1"));
|
||||
static_assert(bpu<int64_t>(dim::time, scalefactor_ratio_type(360*24*3600, 1), power_ratio_type(-1, 1)).abbrev()
|
||||
== bpu_abbrev_type::from_chars("yr360^-1"));
|
||||
static_assert(bpu<int64_t>(dim::time, scalefactor_ratio_type(360*24*3600, 1), power_ratio_type(-1, 2)).abbrev()
|
||||
== bpu_abbrev_type::from_chars("yr360^(-1/2)"));
|
||||
} /*TEST_CASE(bpu_abbrev)*/
|
||||
|
||||
} /*namespace qty*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end bpu.test.cpp */
|
||||
862
xo-unit/utest/mpl_quantity.test.cpp
Normal file
862
xo-unit/utest/mpl_quantity.test.cpp
Normal file
|
|
@ -0,0 +1,862 @@
|
|||
/* @file quantity.test.cpp */
|
||||
|
||||
#include "xo/unit/mpl/quantity.hpp"
|
||||
#include "xo/reflect/Reflect.hpp"
|
||||
//#include <xo/randomgen/random_seed.hpp>
|
||||
//#include <xo/randomgen/xoshiro256.hpp>
|
||||
#include <xo/indentlog/scope.hpp>
|
||||
#include <xo/indentlog/print/tag.hpp>
|
||||
#include <catch2/catch.hpp>
|
||||
#include <compare>
|
||||
|
||||
namespace xo {
|
||||
using xo::unit::quantity;
|
||||
|
||||
using xo::unit::qty::kilograms;
|
||||
|
||||
using xo::unit::qty::meters;
|
||||
using xo::unit::qty::kilometers;
|
||||
|
||||
using xo::unit::qty::milliseconds;
|
||||
using xo::unit::qty::seconds;
|
||||
using xo::unit::qty::minutes;
|
||||
using xo::unit::qty::hours;
|
||||
using xo::unit::qty::volatility30d;
|
||||
using xo::unit::qty::volatility250d;
|
||||
|
||||
using xo::unit::unit_find_bpu_t;
|
||||
using xo::unit::unit_conversion_factor_t;
|
||||
using xo::unit::unit_cartesian_product_t;
|
||||
using xo::unit::unit_cartesian_product;
|
||||
using xo::unit::unit_invert_t;
|
||||
using xo::unit::unit_abbrev_v;
|
||||
using xo::unit::same_dimension_v;
|
||||
using xo::unit::dim;
|
||||
|
||||
using xo::unit::from_ratio;
|
||||
using xo::unit::stringliteral_from_ratio;
|
||||
using xo::unit::ratio2str_aux;
|
||||
using xo::unit::cstr_from_ratio;
|
||||
|
||||
using xo::reflect::Reflect;
|
||||
|
||||
namespace units = xo::unit::units;
|
||||
|
||||
namespace ut {
|
||||
/* use 'testcase' snippet to add test cases here */
|
||||
TEST_CASE("quantity", "[quantity]") {
|
||||
//constexpr bool c_debug_flag = false;
|
||||
|
||||
// can get bits from /dev/random by uncommenting the 2nd line below
|
||||
//uint64_t seed = xxx;
|
||||
//rng::Seed<xoshio256ss> seed;
|
||||
|
||||
//auto rng = xo::rng::xoshiro256ss(seed);
|
||||
|
||||
//scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.quantity"), xtag("foo", foo), ...);
|
||||
//log && log("(A)", xtag("foo", foo));
|
||||
|
||||
quantity<units::second, int64_t> t = seconds(1L);
|
||||
|
||||
REQUIRE(t.scale() == 1);
|
||||
|
||||
static_assert(t.basis_power<dim::time> == 1);
|
||||
static_assert(t.basis_power<dim::mass> == 0);
|
||||
} /*TEST_CASE(quantity)*/
|
||||
|
||||
TEST_CASE("add1", "[quantity]") {
|
||||
constexpr bool c_debug_flag = false;
|
||||
|
||||
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.add1"));
|
||||
|
||||
quantity<units::second, int64_t> t1 = seconds(1);
|
||||
quantity<units::second, int64_t> t2 = seconds(2);
|
||||
|
||||
static_assert(std::same_as<decltype(t1)::unit_type, units::second>);
|
||||
static_assert(std::same_as<decltype(t2)::unit_type, units::second>);
|
||||
|
||||
auto sum = t1 + t2;
|
||||
|
||||
CHECK(strcmp(sum.unit_cstr(), "s") == 0);
|
||||
|
||||
static_assert(std::same_as<decltype(sum)::unit_type, units::second>);
|
||||
static_assert(t1.basis_power<dim::time> == 1);
|
||||
static_assert(t2.basis_power<dim::time> == 1);
|
||||
|
||||
REQUIRE(sum.scale() == 3);
|
||||
|
||||
} /*TEST_CASE(add1)*/
|
||||
|
||||
TEST_CASE("add2", "[quantity]") {
|
||||
constexpr bool c_debug_flag = false;
|
||||
|
||||
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.add2"));
|
||||
|
||||
quantity<units::second, int64_t> t1 = seconds(1);
|
||||
{
|
||||
CHECK(strcmp(t1.unit_cstr(), "s") == 0);
|
||||
CHECK(t1.scale() == 1);
|
||||
}
|
||||
|
||||
auto m2 = minutes(2);
|
||||
|
||||
{
|
||||
static_assert(m2.basis_power<dim::time> == 1);
|
||||
|
||||
log && log(xtag("m2.scale", m2.scale()), xtag("m2.unit", m2.unit_cstr()));
|
||||
|
||||
CHECK(m2.scale() == 2);
|
||||
CHECK(strcmp(m2.unit_cstr(), "min") == 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto m2_sec = m2.in_units_of<units::second, int64_t>();
|
||||
|
||||
static_assert(std::same_as<decltype(m2_sec), int64_t>);
|
||||
|
||||
log && log(XTAG(m2_sec));
|
||||
|
||||
CHECK(m2_sec == 120);
|
||||
}
|
||||
|
||||
quantity<units::second, int64_t> t2 = m2;
|
||||
{
|
||||
auto sum = t1 + t2;
|
||||
|
||||
static_assert(std::same_as<decltype(sum)::unit_type, units::second>);
|
||||
static_assert(sum.basis_power<dim::time> == 1);
|
||||
|
||||
log && log(xtag("t1.unit", t1.unit_cstr()), xtag("t2.unit", t2.unit_cstr()));
|
||||
log && log(xtag("sum.unit", sum.unit_cstr()));
|
||||
|
||||
CHECK(strcmp(t2.unit_cstr(), "s") == 0);
|
||||
CHECK(strcmp(sum.unit_cstr(), "s") == 0);
|
||||
CHECK(sum.scale() == 121);
|
||||
}
|
||||
} /*TEST_CASE(add2)*/
|
||||
|
||||
TEST_CASE("add3", "[quantity]") {
|
||||
quantity<units::second, int64_t> t1 = seconds(1);
|
||||
quantity<units::minute, int64_t> t2 = minutes(2);
|
||||
|
||||
/* sum will take unit from lhs argument to + */
|
||||
auto sum = t1 + t2;
|
||||
|
||||
static_assert(sum.basis_power<dim::time> == 1);
|
||||
static_assert(std::same_as<decltype(sum)::unit_type, units::second>);
|
||||
|
||||
REQUIRE(sum.scale() == 121);
|
||||
} /*TEST_CASE(add3)*/
|
||||
|
||||
TEST_CASE("add4", "[quantity]") {
|
||||
constexpr bool c_debug_flag = false;
|
||||
|
||||
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.add4"));
|
||||
|
||||
using u_kgps_result = unit_cartesian_product<units::kilogram, unit_invert_t<units::second>>;
|
||||
using u_kgps = u_kgps_result::exact_unit_type;
|
||||
using u_gpm_result = unit_cartesian_product<units::gram, unit_invert_t<units::minute>>;
|
||||
using u_gpm = u_gpm_result::exact_unit_type;
|
||||
{
|
||||
static_assert(u_kgps_result::c_scalefactor_inexact == 1.0);
|
||||
|
||||
static_assert(std::same_as<unit_find_bpu_t<u_kgps, dim::mass>::power_type, std::ratio<1>>);
|
||||
static_assert(std::same_as<unit_find_bpu_t<u_kgps, dim::time>::power_type, std::ratio<-1>>);
|
||||
static_assert(std::same_as<unit_find_bpu_t<u_gpm, dim::mass>::power_type, std::ratio<1>>);
|
||||
static_assert(std::same_as<unit_find_bpu_t<u_gpm, dim::time>::power_type, std::ratio<-1>>);
|
||||
|
||||
log && log(xtag("u_kgps", unit_abbrev_v<u_kgps>.c_str()));
|
||||
log && log(xtag("u_gpm", unit_abbrev_v<u_gpm>.c_str()));
|
||||
|
||||
CHECK(strcmp(unit_abbrev_v<u_kgps>.c_str(), "kg.s^-1") == 0);
|
||||
CHECK(strcmp(unit_abbrev_v<u_gpm>.c_str(), "g.min^-1") == 0);
|
||||
|
||||
static_assert(same_dimension_v<u_kgps, u_gpm>);
|
||||
}
|
||||
|
||||
using convert_type = unit_conversion_factor_t<u_kgps, u_gpm>;
|
||||
{
|
||||
log && log(xtag("u_kgps->u_gpm", cstr_from_ratio<convert_type>()));
|
||||
|
||||
CHECK(strcmp(cstr_from_ratio<convert_type>(), "60000") == 0);
|
||||
CHECK(from_ratio<int64_t, convert_type>() == 60000);
|
||||
}
|
||||
|
||||
/* note: in practice probably write
|
||||
* kilograms(0.1) / seconds(1);
|
||||
* but
|
||||
* 1. don't want to exercise quantity {*,/} here;
|
||||
* 2. want to force unit representation
|
||||
*/
|
||||
auto q1 = quantity<u_kgps, double>::promote(0.1);
|
||||
auto q2 = quantity<u_gpm, double>();
|
||||
{
|
||||
q2 = q1;
|
||||
|
||||
static_assert(q1.basis_power<dim::mass> == 1);
|
||||
static_assert(q1.basis_power<dim::time> == -1);
|
||||
static_assert(q2.basis_power<dim::mass> == 1);
|
||||
static_assert(q2.basis_power<dim::time> == -1);
|
||||
|
||||
log && log(XTAG(q1), XTAG(q2));
|
||||
|
||||
CHECK(strcmp(q1.unit_cstr(), "kg.s^-1") == 0);
|
||||
CHECK(q1.scale() == 0.1);
|
||||
|
||||
CHECK(strcmp(q2.unit_cstr(), "g.min^-1") == 0);
|
||||
CHECK(q2.scale() == 6000.0);
|
||||
}
|
||||
} /*TEST_CASE(add4)*/
|
||||
|
||||
TEST_CASE("add5", "[quantity][fractional_dimension]") {
|
||||
constexpr bool c_debug_flag = false;
|
||||
|
||||
// can get bits from /dev/random by uncommenting the 2nd line below
|
||||
//uint64_t seed = xxx;
|
||||
//rng::Seed<xoshio256ss> seed;
|
||||
|
||||
//auto rng = xo::rng::xoshiro256ss(seed);
|
||||
|
||||
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.add5"));
|
||||
//log && log("(A)", xtag("foo", foo));
|
||||
|
||||
auto vol_250d = volatility250d(0.2);
|
||||
{
|
||||
log && log(xtag("vol_250d", vol_250d));
|
||||
|
||||
CHECK(strcmp(vol_250d.unit_cstr(), "yr250^-(1/2)") == 0);
|
||||
CHECK(vol_250d.scale() == 0.2);
|
||||
}
|
||||
|
||||
/* scaling factor from 30-day vol to 250-day vol is sqrt(250/30) ~ 2.88675
|
||||
* so 0.1 -> 0.288675
|
||||
*/
|
||||
auto vol_30d = volatility30d(0.1);
|
||||
{
|
||||
log && log(xtag("vol_30d", vol_30d));
|
||||
|
||||
CHECK(strcmp(vol_30d.unit_cstr(), "mo^-(1/2)") == 0);
|
||||
CHECK(vol_30d.scale() == Approx(0.1).epsilon(1e-6));
|
||||
}
|
||||
|
||||
/* conversion from monthly vol to (250-day) annual vol */
|
||||
|
||||
using u_vol250d = units::volatility_250d;
|
||||
{
|
||||
quantity<u_vol250d, double> q = vol_30d;
|
||||
|
||||
log && log(xtag("q", q));
|
||||
|
||||
CHECK(strcmp(q.unit_cstr(), "yr250^-(1/2)") == 0);
|
||||
CHECK(q.scale() == Approx(0.288675).epsilon(1e-6));
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
auto sum = vol_250d + vol_30d;
|
||||
|
||||
static_assert(sum.basis_power<dim::time, double> == -0.5);
|
||||
|
||||
log && log(XTAG(sum));
|
||||
|
||||
CHECK(strcmp(sum.unit_cstr(), "yr250^-(1/2)") == 0);
|
||||
/* 0.1mo^-(1/2) ~ 0.288675yr250^-(1/2) */
|
||||
CHECK(sum.scale() == Approx(0.4886751).epsilon(1e-6));
|
||||
}
|
||||
} /*TEST_CASE(add5)*/
|
||||
|
||||
|
||||
TEST_CASE("mult1", "[quantity]") {
|
||||
constexpr bool c_debug_flag = false;
|
||||
|
||||
// can get bits from /dev/random by uncommenting the 2nd line below
|
||||
//uint64_t seed = xxx;
|
||||
//rng::Seed<xoshio256ss> seed;
|
||||
|
||||
//auto rng = xo::rng::xoshiro256ss(seed);
|
||||
|
||||
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.mult1"));
|
||||
//log && log("(A)", xtag("foo", foo));
|
||||
|
||||
auto q0 = milliseconds(5);
|
||||
auto q1 = seconds(60);
|
||||
auto q2 = minutes(1);
|
||||
|
||||
{
|
||||
auto r = q0 * q1;
|
||||
|
||||
static_assert(r.basis_power<dim::time> == 2);
|
||||
|
||||
log && log(xtag("q0", q0), xtag("q1", q1), xtag("q0*q1", r));
|
||||
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
|
||||
|
||||
/* taking unit from LHS */
|
||||
REQUIRE(strcmp(r.unit_cstr(), "ms^2") == 0);
|
||||
REQUIRE(r.scale() == 300000);
|
||||
}
|
||||
|
||||
{
|
||||
auto r = q1 * q2;
|
||||
|
||||
static_assert(r.basis_power<dim::time> == 2);
|
||||
|
||||
log && log(xtag("q1", q1), xtag("q2", q2), xtag("q1*q2", r));
|
||||
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
|
||||
|
||||
/* taking unit from LHS */
|
||||
REQUIRE(strcmp(r.unit_cstr(), "s^2") == 0);
|
||||
REQUIRE(r.scale() == 3600);
|
||||
}
|
||||
|
||||
{
|
||||
auto r = q2 * q1;
|
||||
|
||||
static_assert(r.basis_power<dim::time> == 2);
|
||||
|
||||
log && log(xtag("q1", q1), xtag("q2", q2), xtag("r=q2*q1", r));
|
||||
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
|
||||
|
||||
/* taking unit from LHS */
|
||||
CHECK(strcmp(r.unit_cstr(), "min^2") == 0);
|
||||
CHECK(r.scale() == 1);
|
||||
}
|
||||
|
||||
{
|
||||
auto r = q2 * 60;
|
||||
|
||||
static_assert(r.basis_power<dim::time> == 1);
|
||||
static_assert(std::same_as<decltype(r)::repr_type, int>);
|
||||
|
||||
log && log(xtag("q2*60", r));
|
||||
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
|
||||
|
||||
/* preserve units of existing quantity */
|
||||
CHECK(strcmp(r.unit_cstr(), "min") == 0);
|
||||
CHECK(r.scale() == 60);
|
||||
}
|
||||
|
||||
{
|
||||
auto r = q2 * 60U;
|
||||
|
||||
static_assert(r.basis_power<dim::time> == 1);
|
||||
static_assert(std::same_as<decltype(r)::repr_type, uint32_t>);
|
||||
|
||||
log && log(xtag("q2*60U", r));
|
||||
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
|
||||
|
||||
/* preserve units of existing quantity */
|
||||
CHECK(strcmp(r.unit_cstr(), "min") == 0);
|
||||
CHECK(r.scale() == 60U);
|
||||
}
|
||||
|
||||
{
|
||||
auto r = (q2 * 60.5);
|
||||
|
||||
static_assert(r.basis_power<dim::time> == 1);
|
||||
|
||||
/* verify dimension */
|
||||
static_assert(std::same_as<decltype(r)::repr_type, double>);
|
||||
|
||||
log && log(xtag("q2*60.5", q2*60.5));
|
||||
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
|
||||
|
||||
/* preserve units of existing quantity */
|
||||
REQUIRE(strcmp(r.unit_cstr(), "min") == 0);
|
||||
REQUIRE(r.scale() == 60.5);
|
||||
}
|
||||
|
||||
{
|
||||
log && log(xtag("q2*60.5f", q2*60.5f));
|
||||
|
||||
auto r = (q2 * 60.5f);
|
||||
|
||||
/* verify dimension */
|
||||
static_assert(r.basis_power<dim::time> == 1);
|
||||
static_assert(std::same_as<decltype(r)::repr_type, float>);
|
||||
|
||||
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
|
||||
|
||||
/* preserve units of existing quantity */
|
||||
REQUIRE(strcmp(r.unit_cstr(), "min") == 0);
|
||||
REQUIRE(r.scale() == 60.5f);
|
||||
}
|
||||
|
||||
{
|
||||
auto r = 60 * q2;
|
||||
|
||||
static_assert(r.basis_power<dim::time> == 1);
|
||||
static_assert(std::same_as<decltype(r)::repr_type, int>);
|
||||
|
||||
log && log(xtag("60*q2", r));
|
||||
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
|
||||
|
||||
/* preserve units of existing quantity */
|
||||
CHECK(strcmp(r.unit_cstr(), "min") == 0);
|
||||
CHECK(r.scale() == 60);
|
||||
}
|
||||
|
||||
{
|
||||
log && log(xtag("60.5*q2", 60.5*q2));
|
||||
|
||||
auto r = 60.5 * q2;
|
||||
|
||||
static_assert(r.basis_power<dim::time> == 1);
|
||||
|
||||
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
|
||||
static_assert(std::same_as<decltype(r)::repr_type, double>);
|
||||
|
||||
/* preserve units of existing quantity */
|
||||
CHECK(strcmp(r.unit_cstr(), "min") == 0);
|
||||
CHECK(r.scale() == 60.5);
|
||||
}
|
||||
|
||||
{
|
||||
log && log(xtag("60.5f*q2", 60.5f*q2));
|
||||
|
||||
auto r = 60.5f * q2;
|
||||
|
||||
static_assert(r.basis_power<dim::time> == 1);
|
||||
static_assert(std::same_as<decltype(r)::repr_type, float>);
|
||||
|
||||
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
|
||||
|
||||
/* preserve units of existing quantity */
|
||||
CHECK(strcmp(r.unit_cstr(), "min") == 0);
|
||||
CHECK(r.scale() == 60.5);
|
||||
}
|
||||
} /*TEST_CASE(mult1)*/
|
||||
|
||||
TEST_CASE("div1", "[quantity]") {
|
||||
constexpr bool c_debug_flag = false;
|
||||
|
||||
// can get bits from /dev/random by uncommenting the 2nd line below
|
||||
//uint64_t seed = xxx;
|
||||
//rng::Seed<xoshio256ss> seed;
|
||||
|
||||
//auto rng = xo::rng::xoshiro256ss(seed);
|
||||
|
||||
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.div1"));
|
||||
//log && log("(A)", xtag("foo", foo));
|
||||
|
||||
auto q0 = milliseconds(5);
|
||||
auto q1 = milliseconds(10);
|
||||
|
||||
{
|
||||
/* repr_type adopts argument to milliseconds() */
|
||||
static_assert(std::same_as<decltype(q0)::repr_type, int>);
|
||||
static_assert(std::same_as<decltype(q1)::repr_type, int>);
|
||||
|
||||
auto r = q0/q1;
|
||||
|
||||
log && log(xtag("q0", q0), xtag("q1", q1), xtag("q0/q1", r));
|
||||
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
|
||||
|
||||
/* verify dimensionless + no type promotion */
|
||||
static_assert(std::same_as<decltype(r), int>);
|
||||
/* verify scale (truncate)*/
|
||||
REQUIRE(r == 0);
|
||||
}
|
||||
|
||||
auto q0p = milliseconds(5.0);
|
||||
|
||||
{
|
||||
static_assert(std::same_as<decltype(q0p)::repr_type, double>);
|
||||
|
||||
auto r = q0p/q1;
|
||||
static_assert(std::same_as<decltype(r), double>);
|
||||
|
||||
log && log(XTAG(q0p), xtag("q0p/q1", r));
|
||||
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
|
||||
|
||||
/* verify dimension */
|
||||
static_assert(std::same_as<decltype(r), double>);
|
||||
|
||||
/* verify scale */
|
||||
REQUIRE(r == 0.5);
|
||||
}
|
||||
|
||||
auto r1 = 1.0 / q0;
|
||||
|
||||
{
|
||||
log && log(XTAG(q0), xtag("r1=1.0/q0", r1));
|
||||
|
||||
/* verify dimension */
|
||||
static_assert(r1.basis_power<dim::time> == -1);
|
||||
|
||||
/* verify scale */
|
||||
REQUIRE(r1.scale() == 0.2);
|
||||
}
|
||||
} /*TEST_CASE(div1)*/
|
||||
|
||||
TEST_CASE("div2", "[quantity]") {
|
||||
constexpr bool c_debug_flag = false;
|
||||
|
||||
// can get bits from /dev/random by uncommenting the 2nd line below
|
||||
//uint64_t seed = xxx;
|
||||
//rng::Seed<xoshio256ss> seed;
|
||||
|
||||
//auto rng = xo::rng::xoshiro256ss(seed);
|
||||
|
||||
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.div2"));
|
||||
|
||||
auto q0 = milliseconds(5);
|
||||
auto q1 = milliseconds(20.0);
|
||||
|
||||
{
|
||||
auto r = q0/q1;
|
||||
|
||||
log && log(xtag("q0", q0), xtag("q1", q1), xtag("q0/q1", r));
|
||||
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
|
||||
|
||||
/* verify dimension */
|
||||
static_assert(std::same_as<decltype(r), double>);
|
||||
|
||||
/* verify scale */
|
||||
REQUIRE(r == 0.25);
|
||||
}
|
||||
|
||||
{
|
||||
auto r = q1/q0;
|
||||
|
||||
log && log(xtag("q0", q0), xtag("q1", q1), xtag("q1/q0", r));
|
||||
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
|
||||
|
||||
/* verify dimension */
|
||||
static_assert(std::same_as<decltype(r), double>);
|
||||
|
||||
/* verify scale */
|
||||
REQUIRE(r == 4.0);
|
||||
}
|
||||
|
||||
{
|
||||
auto r = q0/(q1*q1);
|
||||
|
||||
log && log(xtag("q0", q0), xtag("q1", q1), xtag("q0/(q1*q1)", r));
|
||||
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
|
||||
|
||||
/* verify dimension */
|
||||
static_assert(r.basis_power<dim::time> == -1);
|
||||
|
||||
/* verify scale */
|
||||
REQUIRE(r.scale() == 0.0125);
|
||||
}
|
||||
|
||||
{
|
||||
auto r = (q0*q0)/q1;
|
||||
|
||||
log && log(xtag("q0", q0), xtag("q1", q1), xtag("(q0*q0)/q1", r));
|
||||
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
|
||||
|
||||
/* verify dimension */
|
||||
static_assert(r.basis_power<dim::time> == 1);
|
||||
|
||||
/* verify scale */
|
||||
REQUIRE(r.scale() == 1.25);
|
||||
}
|
||||
|
||||
} /*TEST_CASE(div2)*/
|
||||
|
||||
TEST_CASE("div3", "[quantity]") {
|
||||
constexpr bool c_debug_flag = false;
|
||||
|
||||
// can get bits from /dev/random by uncommenting the 2nd line below
|
||||
//uint64_t seed = xxx;
|
||||
//rng::Seed<xoshio256ss> seed;
|
||||
|
||||
//auto rng = xo::rng::xoshiro256ss(seed);
|
||||
|
||||
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.div3"));
|
||||
|
||||
auto q0 = milliseconds(5);
|
||||
auto q1 = milliseconds(20.0);
|
||||
|
||||
{
|
||||
auto r = q0/q1;
|
||||
|
||||
log && log(XTAG(q0), XTAG(q1), xtag("q0/q1", r));
|
||||
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
|
||||
|
||||
/* verify dimension */
|
||||
static_assert(std::same_as<decltype(r), double>);
|
||||
|
||||
/* verify scale */
|
||||
REQUIRE(r == 0.25);
|
||||
}
|
||||
|
||||
{
|
||||
auto r = q1/q0;
|
||||
|
||||
log && log(xtag("q0", q0), xtag("q1", q1), xtag("q1/q0", r));
|
||||
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
|
||||
|
||||
/* verify dimension */
|
||||
static_assert(std::same_as<decltype(r), double>);
|
||||
|
||||
/* verify scale */
|
||||
REQUIRE(r == 4.0);
|
||||
}
|
||||
|
||||
{
|
||||
auto r = q0/(q1*q1);
|
||||
|
||||
log && log(xtag("q0", q0), xtag("q1", q1), xtag("q0/(q1*q1)", r));
|
||||
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
|
||||
|
||||
/* verify dimension */
|
||||
static_assert(r.basis_power<dim::time> == -1);
|
||||
|
||||
/* verify scale */
|
||||
REQUIRE(r.scale() == 0.0125);
|
||||
}
|
||||
|
||||
{
|
||||
auto r = (q0*q0)/q1;
|
||||
|
||||
log && log(xtag("q0", q0), xtag("q1", q1), xtag("(q0*q0)/q1", r));
|
||||
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
|
||||
|
||||
/* verify dimension */
|
||||
static_assert(r.basis_power<dim::time> == 1);
|
||||
|
||||
/* verify scale */
|
||||
REQUIRE(r.scale() == 1.25);
|
||||
}
|
||||
|
||||
} /*TEST_CASE(div3)*/
|
||||
|
||||
TEST_CASE("div4", "[quantity]") {
|
||||
/* test with exact scalefactor */
|
||||
|
||||
constexpr bool c_debug_flag = false;
|
||||
|
||||
// can get bits from /dev/random by uncommenting the 2nd line below
|
||||
//uint64_t seed = xxx;
|
||||
//rng::Seed<xoshio256ss> seed;
|
||||
|
||||
//auto rng = xo::rng::xoshiro256ss(seed);
|
||||
|
||||
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.div4"));
|
||||
//log && log("(A)", xtag("foo", foo));
|
||||
|
||||
auto q1 = milliseconds(1);
|
||||
auto q2 = minutes(1);
|
||||
|
||||
auto r = q1 / q2.with_repr<double>();
|
||||
|
||||
/* 0.1/sqrt(30dy) ~ 0.288675/sqrt(250dy),
|
||||
* so q1/q2 ~ 0.6928
|
||||
*/
|
||||
|
||||
log && log(XTAG(q1), XTAG(q2), xtag("q1/q2", r));
|
||||
|
||||
/* verify dimensionless result */
|
||||
static_assert(std::same_as<decltype(r), double>);
|
||||
|
||||
/* verify scale of result */
|
||||
CHECK(r == Approx(0.00001666667).epsilon(1e-6));
|
||||
|
||||
} /*TEST_CASE(div4)*/
|
||||
|
||||
TEST_CASE("div5", "[quantity]") {
|
||||
/* test with inexact scalefactor */
|
||||
|
||||
constexpr bool c_debug_flag = false;
|
||||
|
||||
// can get bits from /dev/random by uncommenting the 2nd line below
|
||||
//uint64_t seed = xxx;
|
||||
//rng::Seed<xoshio256ss> seed;
|
||||
|
||||
//auto rng = xo::rng::xoshiro256ss(seed);
|
||||
|
||||
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.div5"));
|
||||
//log && log("(A)", xtag("foo", foo));
|
||||
|
||||
auto q1 = volatility250d(0.2);
|
||||
auto q2 = volatility30d(0.1);
|
||||
|
||||
auto r = q1/q2;
|
||||
|
||||
/* 0.1/sqrt(30dy) ~ 0.288675/sqrt(250dy),
|
||||
* so q1/q2 ~ 0.6928
|
||||
*/
|
||||
|
||||
log && log(XTAG(q1), XTAG(q2), XTAG(q1/q2));
|
||||
|
||||
/* verify dimensionless result */
|
||||
static_assert(std::same_as<decltype(r), double>);
|
||||
|
||||
/* verify scale of result */
|
||||
CHECK(r == Approx(0.692820323).epsilon(1e-6));
|
||||
|
||||
} /*TEST_CASE(div5)*/
|
||||
|
||||
TEST_CASE("muldiv5", "[quantity]") {
|
||||
constexpr bool c_debug_flag = false;
|
||||
|
||||
// can get bits from /dev/random by uncommenting the 2nd line below
|
||||
//uint64_t seed = xxx;
|
||||
//rng::Seed<xoshio256ss> seed;
|
||||
|
||||
//auto rng = xo::rng::xoshiro256ss(seed);
|
||||
|
||||
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.muldiv5"));
|
||||
//log && log("(A)", xtag("foo", foo));
|
||||
|
||||
auto t = milliseconds(10);
|
||||
auto m = kilograms(2.5);
|
||||
|
||||
auto a = m / (t * t);
|
||||
|
||||
/* 0.1/sqrt(30dy) ~ 0.288675/sqrt(250dy),
|
||||
* so q1/q2 ~ 0.6928
|
||||
*/
|
||||
|
||||
log && log(XTAG(m), XTAG(t), xtag("a=m.t^-2", a));
|
||||
|
||||
/* verify dimensions of result + sticky units */
|
||||
CHECK(strcmp(t.unit_cstr(), "ms") == 0);
|
||||
CHECK(strcmp(m.unit_cstr(), "kg") == 0);
|
||||
CHECK(strcmp(a.unit_cstr(), "kg.ms^-2") == 0);
|
||||
|
||||
CHECK(a.scale() == 0.025);
|
||||
|
||||
/* verify scale of result */
|
||||
//CHECK(r == Approx(0.692820323).epsilon(1e-6));
|
||||
|
||||
} /*TEST_CASE(muldiv5)*/
|
||||
|
||||
TEST_CASE("rescale", "[quantity]") {
|
||||
constexpr bool c_debug_flag = false;
|
||||
|
||||
// can get bits from /dev/random by uncommenting the 2nd line below
|
||||
//uint64_t seed = xxx;
|
||||
//rng::Seed<xoshio256ss> seed;
|
||||
|
||||
//auto rng = xo::rng::xoshiro256ss(seed);
|
||||
|
||||
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.rescale"));
|
||||
//log && log("(A)", xtag("foo", foo));
|
||||
|
||||
auto q = kilograms(150.0) / minutes(1); /* 150.0kg.min^-1 */
|
||||
|
||||
CHECK(strcmp(q.unit_cstr(), "kg.min^-1") == 0);
|
||||
CHECK(q.scale() == 150.0);
|
||||
|
||||
log && log(XTAG(q));
|
||||
|
||||
namespace u = xo::unit::units;
|
||||
|
||||
auto q1 = q.with_basis_unit<u::millisecond>(); /* 0.0025kg.ms^-1 */
|
||||
|
||||
CHECK(strcmp(q1.unit_cstr(), "kg.ms^-1") == 0);
|
||||
CHECK(q1.scale() == 0.0025);
|
||||
|
||||
log && log(XTAG(q1));
|
||||
|
||||
auto q2 = q1.with_basis_unit<u::gram>(); /* 2.5g.ms^-1 */
|
||||
|
||||
CHECK(strcmp(q2.unit_cstr(), "g.ms^-1") == 0);
|
||||
CHECK(q2.scale() == 2.5);
|
||||
|
||||
log && log(XTAG(q2));
|
||||
|
||||
auto q3 = q2.with_basis_unit<u::second>(); /* 2500g.s^-1 */
|
||||
|
||||
CHECK(strcmp(q3.unit_cstr(), "g.s^-1") == 0);
|
||||
CHECK(q3.scale() == 2500.0);
|
||||
|
||||
log && log(XTAG(q3));
|
||||
} /*TEST_CASE(rescale)*/
|
||||
|
||||
TEST_CASE("rescale2", "[quantity]") {
|
||||
constexpr bool c_debug_flag = false;
|
||||
|
||||
// can get bits from /dev/random by uncommenting the 2nd line below
|
||||
//uint64_t seed = xxx;
|
||||
//rng::Seed<xoshio256ss> seed;
|
||||
|
||||
//auto rng = xo::rng::xoshiro256ss(seed);
|
||||
|
||||
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.rescale2"));
|
||||
//log && log("(A)", xtag("foo", foo));
|
||||
|
||||
namespace u = xo::unit::unit_qty;
|
||||
|
||||
auto q1 = kilometers(150.0) / u::hour;
|
||||
auto q2 = q1.with_units_from(u::meter / u::second);
|
||||
|
||||
log && log(XTAG(q1), XTAG(q2));
|
||||
} /*TEST_CASE(rescale2)*/
|
||||
|
||||
TEST_CASE("compare1", "[quantity]") {
|
||||
constexpr bool c_debug_flag = false;
|
||||
|
||||
// can get bits from /dev/random by uncommenting the 2nd line below
|
||||
//uint64_t seed = xxx;
|
||||
//rng::Seed<xoshio256ss> seed;
|
||||
|
||||
//auto rng = xo::rng::xoshiro256ss(seed);
|
||||
|
||||
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.compare1"));
|
||||
//log && log("(A)", xtag("foo", foo));
|
||||
|
||||
namespace u = xo::unit::unit_qty;
|
||||
|
||||
auto q1 = kilometers(150.0) / u::hour;
|
||||
auto q2 = kilometers(100.0) / u::hour;
|
||||
|
||||
CHECK(is_gt(q1 <=> q2));
|
||||
CHECK(is_eq(q1 <=> q1));
|
||||
CHECK(is_lt(q2 <=> q1));
|
||||
CHECK(q1 == q1);
|
||||
CHECK(q1 != q2);
|
||||
CHECK(q1 >= q1);
|
||||
CHECK(q1 <= q1);
|
||||
|
||||
CHECK(q1 > q2);
|
||||
CHECK(q1 >= q2);
|
||||
|
||||
CHECK(q2 < q1);
|
||||
CHECK(q2 <= q1);
|
||||
|
||||
log && log(XTAG(q1), XTAG(q2), XTAG(is_gt(q1<=>q2)));
|
||||
} /*TEST_CASE(compare1)*/
|
||||
|
||||
TEST_CASE("compare2", "[quantity]") {
|
||||
constexpr bool c_debug_flag = false;
|
||||
|
||||
// can get bits from /dev/random by uncommenting the 2nd line below
|
||||
//uint64_t seed = xxx;
|
||||
//rng::Seed<xoshio256ss> seed;
|
||||
|
||||
//auto rng = xo::rng::xoshiro256ss(seed);
|
||||
|
||||
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.compare2"));
|
||||
//log && log("(A)", xtag("foo", foo));
|
||||
|
||||
namespace u = xo::unit::unit_qty;
|
||||
|
||||
auto q1 = kilometers(150.0) / u::hour;
|
||||
auto q2 = meters(30.0) / u::second;
|
||||
|
||||
CHECK(is_gt(q1 <=> q2));
|
||||
CHECK(is_eq(q1 <=> q1));
|
||||
CHECK(is_lt(q2 <=> q1));
|
||||
CHECK(q1 == q1);
|
||||
CHECK(q1 != q2);
|
||||
CHECK(q1 >= q1);
|
||||
CHECK(q1 <= q1);
|
||||
|
||||
CHECK(q1 > q2);
|
||||
CHECK(q1 >= q2);
|
||||
|
||||
CHECK(q2 < q1);
|
||||
CHECK(q2 <= q1);
|
||||
|
||||
log && log(XTAG(q1), XTAG(q2), XTAG(is_gt(q1<=>q2)));
|
||||
} /*TEST_CASE(compare2)*/
|
||||
|
||||
} /*namespace ut*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end quantity.test.cpp */
|
||||
380
xo-unit/utest/mpl_unit.test.cpp
Normal file
380
xo-unit/utest/mpl_unit.test.cpp
Normal file
|
|
@ -0,0 +1,380 @@
|
|||
/* @file mpl_unit.test.cpp */
|
||||
|
||||
//#include "native_bpu.hpp"
|
||||
#include "xo/unit/mpl/quantity.hpp"
|
||||
//#include "xo/unit/unit.hpp"
|
||||
//#include "xo/unit/Quantity2_iostream.hpp"
|
||||
//#include "xo/unit/Quantity2.hpp"
|
||||
//#include "xo/unit/scaled_unit_iostream.hpp"
|
||||
//#include "xo/unit/natural_unit.hpp"
|
||||
//#include "xo/unit/natural_unit_iostream.hpp"
|
||||
//#include "xo/unit/bpu_store.hpp"
|
||||
//#include "xo/unit/native_bpu2.hpp"
|
||||
//#include "xo/unit/native_bpu2_iostream.hpp"
|
||||
//#include "xo/unit/basis_unit2.hpp"
|
||||
//#include "xo/unit/dim_util2.hpp"
|
||||
#include "xo/reflect/Reflect.hpp"
|
||||
//#include "xo/cxxutil/demangle.hpp"
|
||||
#include "xo/indentlog/scope.hpp"
|
||||
#include "xo/indentlog/print/tag.hpp"
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
namespace xo {
|
||||
namespace ut {
|
||||
/* compile-time tests */
|
||||
|
||||
using xo::reflect::Reflect;
|
||||
|
||||
//namespace su2 = xo::unit::su2;
|
||||
//using xo::unit::Quantity2;
|
||||
using xo::unit::dim;
|
||||
//using xo::unit::basis_unit2_abbrev_type;
|
||||
//using xo::unit::native_unit2;
|
||||
//using xo::unit::native_unit2_v;
|
||||
//using xo::unit::scalefactor_ratio_type;
|
||||
//using xo::unit::units::scaled_native_unit2_abbrev;
|
||||
//using xo::unit::units::scaled_native_unit2_abbrev_v;
|
||||
//using xo::unit::basis_unit2;
|
||||
//using xo::unit::abbrev::basis_unit2_abbrev;;
|
||||
//using xo::unit::bpu2_abbrev_type;
|
||||
//using xo::unit::abbrev::bpu2_abbrev;
|
||||
//using xo::unit::basis_unit2_store;
|
||||
//using xo::unit::power_ratio_type;
|
||||
//using xo::unit::abbrev::flatstring_from_exponent;
|
||||
//using xo::unit::bpu2;
|
||||
//using xo::unit::detail::bpu2_rescale;
|
||||
//using xo::unit::detail::bpu2_product;
|
||||
//using xo::unit::natural_unit;
|
||||
//using xo::unit::bpu_array_maker;
|
||||
//using xo::unit::detail::nu_product;
|
||||
//using xo::unit::unit_qty;
|
||||
|
||||
using xo::unit::native_unit_abbrev_v;
|
||||
using xo::unit::units::scaled_native_unit_abbrev_v;
|
||||
//using xo::unit::native_dim_abbrev;
|
||||
using xo::unit::stringliteral_compare;
|
||||
using xo::unit::literal_size_v;
|
||||
using xo::unit::stringliteral_from_digit;
|
||||
using xo::unit::stringliteral_from_int_v;
|
||||
using xo::unit::stringliteral;
|
||||
#ifndef __clang__
|
||||
using xo::unit::stringliteral_concat;
|
||||
using xo::unit::stringliteral_from_ratio;
|
||||
using xo::unit::bpu_assemble_abbrev_helper;
|
||||
using xo::unit::bpu_assemble_abbrev;
|
||||
#endif
|
||||
using xo::unit::bpu_node;
|
||||
using xo::unit::wrap_unit;
|
||||
using xo::unit::unit_abbrev_v;
|
||||
//using xo::unit::dim_abbrev_v;
|
||||
using xo::unit::di_cartesian_product;
|
||||
using xo::unit::di_cartesian_product1;
|
||||
using xo::unit::unit_cartesian_product_t;
|
||||
using xo::unit::bpu_cartesian_product;
|
||||
using xo::unit::bpu_cartesian_product_helper;
|
||||
using xo::unit::unit_invert_t;
|
||||
using xo::unit::units::gram;
|
||||
using xo::unit::units::second;
|
||||
using xo::print::ccs;
|
||||
|
||||
template <typename T>
|
||||
int unused()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
constexpr bool unused_same(typename std::enable_if_t<std::is_same<T1, T2>::value, bool> result = true)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
TEST_CASE("native_unit_abbrev", "[native_dim_abbrev]") {
|
||||
constexpr bool c_debug_flag = true;
|
||||
|
||||
// can get bits from /dev/random by uncommenting the 2nd line below
|
||||
//uint64_t seed = xxx;
|
||||
//rng::Seed<xoshio256ss> seed;
|
||||
|
||||
//auto rng = xo::rng::xoshiro256ss(seed);
|
||||
|
||||
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.native_dim_abbrev"));
|
||||
//log && log("(A)", xtag("foo", foo));
|
||||
|
||||
/* NOTE: the .value_ expression below will fail to compile if missing specialization for
|
||||
* native_dim_abbrev on native_dim_id::foo; that's the point :)
|
||||
*/
|
||||
|
||||
REQUIRE(strcmp(scaled_native_unit_abbrev_v<dim::mass, std::ratio<1>>.value_, "g") == 0);
|
||||
REQUIRE(strcmp(scaled_native_unit_abbrev_v<dim::time, std::ratio<1>>.value_, "s") == 0);
|
||||
REQUIRE(strcmp(scaled_native_unit_abbrev_v<dim::currency, std::ratio<1>>.value_, "ccy") == 0);
|
||||
REQUIRE(strcmp(scaled_native_unit_abbrev_v<dim::price, std::ratio<1>>.value_, "px") == 0);
|
||||
|
||||
#ifdef OBSOLETE
|
||||
REQUIRE(strcmp(native_dim_abbrev<dim::mass>().value_, "") != 0);
|
||||
REQUIRE(strcmp(native_dim_abbrev<dim::time>().value_, "") != 0);
|
||||
REQUIRE(strcmp(native_dim_abbrev<dim::currency>().value_, "") != 0);
|
||||
REQUIRE(strcmp(native_dim_abbrev<dim::price>().value_, "") != 0);
|
||||
#endif
|
||||
|
||||
static_assert(stringliteral_compare(stringliteral_from_digit(0), stringliteral("0")) == 0);
|
||||
static_assert(stringliteral_compare(stringliteral_from_digit(1), stringliteral("1")) == 0);
|
||||
static_assert(stringliteral_compare(stringliteral_from_digit(9), stringliteral("9")) == 0);
|
||||
|
||||
static_assert(literal_size_v<0> == 1);
|
||||
static_assert(literal_size_v<10> == 2);
|
||||
static_assert(literal_size_v<99> == 2);
|
||||
static_assert(literal_size_v<100> == 3);
|
||||
static_assert(literal_size_v<999> == 3);
|
||||
|
||||
static_assert(stringliteral_compare(stringliteral_from_int_v<0>(), stringliteral("0")) == 0);
|
||||
static_assert(stringliteral_compare(stringliteral_from_int_v<9>(), stringliteral("9")) == 0);
|
||||
|
||||
static_assert(stringliteral_compare(stringliteral_from_int_v<1, 1, false>(), stringliteral("1")) == 0);
|
||||
|
||||
|
||||
static_assert(stringliteral_compare(stringliteral_from_int_v<9, 1, false>(), stringliteral("9")) == 0);
|
||||
static_assert(stringliteral_compare(stringliteral_from_int_v<9>(), stringliteral("9")) == 0);
|
||||
|
||||
/* NOTE: clang16 complains starting here; gcc is fine */
|
||||
|
||||
#ifndef __clang__
|
||||
if constexpr (stringliteral_concat("a", "b").size() == 3) {
|
||||
REQUIRE(true);
|
||||
} else {
|
||||
REQUIRE(false);
|
||||
}
|
||||
|
||||
static_assert(stringliteral_compare(stringliteral_concat("hello", " ", "world"),
|
||||
stringliteral("hello world")) == 0);
|
||||
|
||||
static_assert(stringliteral_compare(stringliteral_from_int_v<10, 2, false>(), stringliteral("10")) == 0);
|
||||
static_assert(stringliteral_compare(stringliteral_from_int_v<10>(), stringliteral("10")) == 0);
|
||||
|
||||
static_assert(stringliteral_compare(stringliteral_from_int_v<99, 2, false>(), stringliteral("99")) == 0);
|
||||
static_assert(stringliteral_compare(stringliteral_from_int_v<99>(), stringliteral("99")) == 0);
|
||||
|
||||
static_assert(stringliteral_compare(stringliteral_from_int_v<100, 3, false>(), stringliteral("100")) == 0);
|
||||
static_assert(stringliteral_compare(stringliteral_from_int_v<100>(), stringliteral("100")) == 0);
|
||||
|
||||
static_assert(stringliteral_compare(stringliteral_from_int_v<999, 3, false>(), stringliteral("999")) == 0);
|
||||
static_assert(stringliteral_compare(stringliteral_from_int_v<999>(), stringliteral("999")) == 0);
|
||||
|
||||
//std::cerr << "test=" << stringliteral_from_int_v<-1, 2, true>().value_ << std::endl;
|
||||
|
||||
static_assert(stringliteral_compare(stringliteral_from_int_v<-1, 2, true>(), stringliteral("-1")) == 0);
|
||||
static_assert(stringliteral_compare(stringliteral_from_int_v<-1>(), stringliteral("-1")) == 0);
|
||||
|
||||
static_assert(stringliteral_compare(stringliteral_from_int_v<-9, 2, true>(), stringliteral("-9")) == 0);
|
||||
static_assert(stringliteral_compare(stringliteral_from_int_v<-9>(), stringliteral("-9")) == 0);
|
||||
|
||||
static_assert(stringliteral_compare(stringliteral_from_int_v<-10, 3, true>(), stringliteral("-10")) == 0);
|
||||
static_assert(stringliteral_compare(stringliteral_from_int_v<-10>(), stringliteral("-10")) == 0);
|
||||
|
||||
static_assert(stringliteral_compare(stringliteral_from_int_v<-99, 3, true>(), stringliteral("-99")) == 0);
|
||||
static_assert(stringliteral_compare(stringliteral_from_int_v<-99>(), stringliteral("-99")) == 0);
|
||||
|
||||
static_assert(stringliteral_compare(stringliteral_from_int_v<-100, 4, true>(), stringliteral("-100")) == 0);
|
||||
static_assert(stringliteral_compare(stringliteral_from_int_v<-100>(), stringliteral("-100")) == 0);
|
||||
|
||||
static_assert(stringliteral_compare(stringliteral_from_int_v<-999, 4, true>(), stringliteral("-999")) == 0);
|
||||
static_assert(stringliteral_compare(stringliteral_from_int_v<-999>(), stringliteral("-999")) == 0);
|
||||
|
||||
static_assert(stringliteral_compare(stringliteral_from_ratio<std::ratio<2,3>>(), stringliteral("(2/3)")) == 0);
|
||||
static_assert(stringliteral_compare(stringliteral_from_ratio<std::ratio<4,6>>(), stringliteral("(2/3)")) == 0);
|
||||
|
||||
static_assert(stringliteral_compare(stringliteral_from_ratio<std::ratio<-1>>(), stringliteral("-1")) == 0);
|
||||
static_assert(stringliteral_compare(stringliteral_from_ratio<std::ratio<-2>>(), stringliteral("-2")) == 0);
|
||||
static_assert(stringliteral_compare(stringliteral_from_ratio<std::ratio<-6,3>>(), stringliteral("-2")) == 0);
|
||||
static_assert(stringliteral_compare(stringliteral_from_ratio<std::ratio<-3,2>>(), stringliteral("-(3/2)")) == 0);
|
||||
static_assert(stringliteral_compare(stringliteral_from_ratio<std::ratio<3,-2>>(), stringliteral("-(3/2)")) == 0);
|
||||
static_assert(stringliteral_compare(stringliteral_from_ratio<std::ratio<-1,2>>(), stringliteral("-(1/2)")) == 0);
|
||||
static_assert(stringliteral_compare(stringliteral_from_ratio<std::ratio<1,2>>(), stringliteral("(1/2)")) == 0);
|
||||
static_assert(stringliteral_compare(stringliteral_from_ratio<std::ratio<3,2>>(), stringliteral("(3/2)")) == 0);
|
||||
|
||||
//log && log(xtag("ratio<2>", stringliteral_from_ratio<std::ratio<2>>().c_str()));
|
||||
static_assert(stringliteral_compare(stringliteral_from_ratio<std::ratio<2>>(), stringliteral("2")) == 0);
|
||||
|
||||
static_assert(stringliteral_compare(bpu_assemble_abbrev_helper<dim::mass, std::ratio<1>, std::ratio<1>>(), stringliteral("g")) == 0);
|
||||
//log && log(xtag("s^(-1/2)", bpu_assemble_abbrev_helper<dim::time, std::ratio<1>, std::ratio<-1,2>>().c_str()));
|
||||
static_assert(stringliteral_compare(bpu_assemble_abbrev_helper<dim::time, std::ratio<1>, std::ratio<-1,2>>(), stringliteral("s^-(1/2)")) == 0);
|
||||
//stringliteral_compare(stringliteral_from_ratio<std::ratio<2>>(), stringliteral("^2")) == 0);
|
||||
#endif
|
||||
|
||||
//static_assert(stringliteral_compare(stringliteral_from_int_v<10>(), obs::stringliteral("10")) == 0);
|
||||
|
||||
//REQUIRE(strcmp(obs::stringliteral_from_digit(1).value_, "1") == 0);
|
||||
//REQUIRE(strcmp(obs::ratio2str<std::ratio<1>>().value_, "") == 0);
|
||||
|
||||
} /*TEST_CASE(native_dim_abbrev)*/
|
||||
|
||||
TEST_CASE("dimension", "[dimension]") {
|
||||
constexpr bool c_debug_flag = false;
|
||||
|
||||
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.dimension"));
|
||||
//log && log("(A)", xtag("foo", foo));
|
||||
|
||||
using t1 = unit::bpu<unit::dim::currency, std::ratio<1,1>>;
|
||||
|
||||
static_assert(t1::c_native_dim == unit::dim::currency);
|
||||
static_assert(t1::power_type::num == 1);
|
||||
static_assert(t1::power_type::den == 1);
|
||||
|
||||
using t2 = unit::bpu<unit::dim::time, std::ratio<1>, std::ratio<-1,2>>;
|
||||
|
||||
static_assert(t2::c_native_dim == unit::dim::time);
|
||||
static_assert(t2::power_type::num == -1);
|
||||
static_assert(t2::power_type::den == 2);
|
||||
|
||||
using dim1 = wrap_unit<std::ratio<1>, bpu_node<t1>>;
|
||||
using d1 = dim1::dim_type; /* ccy */
|
||||
REQUIRE(unused_same<d1::front_type, t1>());
|
||||
REQUIRE(unused_same<unit::lookup_bpu<d1, 0>::power_unit_type, t1>());
|
||||
#ifdef NOT_USING
|
||||
static_assert(unit::lo_basis_elt_of<d1>::c_lo_basis == t1::c_basis);
|
||||
#endif
|
||||
|
||||
static_assert(unit::native_lo_bwp_of<d1>::bwp_type::c_index == 0);
|
||||
static_assert(unit::native_lo_bwp_of<d1>::bwp_type::c_basis == unit::dim::currency);
|
||||
|
||||
|
||||
using dim2 = wrap_unit<std::ratio<1>, bpu_node<t2>>;
|
||||
using d2 = dim2::dim_type; /* t^(-1/2) */
|
||||
REQUIRE(unused_same<d2::front_type, t2>());
|
||||
REQUIRE(unused_same<unit::lookup_bpu<d2, 0>::power_unit_type, t2>());
|
||||
static_assert(unit::native_lo_bwp_of<d2>::bwp_type::c_index == 0);
|
||||
static_assert(unit::native_lo_bwp_of<d2>::bwp_type::c_basis == unit::dim::time);
|
||||
|
||||
using dim3 = wrap_unit<std::ratio<1>, bpu_node<t1, bpu_node<t2>>>;
|
||||
using d3 = dim3::dim_type; /* ccy.t^(-1/2) */
|
||||
REQUIRE(unused_same<unit::lookup_bpu<d3, 0>::power_unit_type, t1>());
|
||||
|
||||
{
|
||||
using type = unit::lookup_bpu<d3, 1>::power_unit_type;
|
||||
//std::cerr << "unit::power_unit_of<d3,1>::power_unit_type" << xtag("type", reflect::type_name<type>()) << std::endl;
|
||||
|
||||
REQUIRE(unused_same<type, t2>());
|
||||
}
|
||||
|
||||
#ifdef NOT_USING
|
||||
static_assert(unit::lo_basis_elt_of<d3>::c_lo_basis == t2::c_basis);
|
||||
#endif
|
||||
|
||||
/* lowest is in pos 1, beacuse t2=time before t1=currency */
|
||||
static_assert(unit::native_lo_bwp_of<d3>::bwp_type::c_index == 1);
|
||||
|
||||
static_assert(unused_same<unit::without_elt<d3, 0>::dim_type, d2>());
|
||||
//using type = unit::without_elt<d3, 1>::dim_type;
|
||||
//std::cerr << "unit::without_elt<d3,1>::dim_type" << xtag("type", reflect::type_name<type>()) << std::endl;
|
||||
static_assert(unused_same<unit::without_elt<d3, 1>::dim_type, d1>());
|
||||
|
||||
|
||||
using d3b = wrap_unit<std::ratio<1>,
|
||||
bpu_node<t2, bpu_node<t1>>>::dim_type; /* t^(-1/2).ccy */
|
||||
//using d3b = unit::dimension_impl<t2, unit::dimension_impl<t1>>; /* t^(-1/2).ccy */
|
||||
REQUIRE(unused_same<unit::lookup_bpu<d3b, 0>::power_unit_type, t2>());
|
||||
REQUIRE(unused_same<unit::lookup_bpu<d3b, 1>::power_unit_type, t1>());
|
||||
|
||||
/* lowest is in pos 0 */
|
||||
static_assert(unit::native_lo_bwp_of<d3b>::bwp_type::c_index == 0);
|
||||
|
||||
static_assert(unused_same<unit::without_elt<d3b, 0>::dim_type, d1>());
|
||||
static_assert(unused_same<unit::without_elt<d3b, 1>::dim_type, d2>());
|
||||
|
||||
static_assert(unused_same<unit::canonical_t<d3>, unit::canonical_t<d3b>>());
|
||||
|
||||
log && log(xtag("d1.abbrev", unit_abbrev_v<dim1>.c_str()));
|
||||
log && log(xtag("d2.abbrev", unit_abbrev_v<dim2>.c_str()));
|
||||
log && log(xtag("d3.abbrev", unit_abbrev_v<dim3>.c_str()));
|
||||
}
|
||||
|
||||
TEST_CASE("dimension2", "[dimension2]") {
|
||||
constexpr bool c_debug_flag = false;
|
||||
|
||||
// can get bits from /dev/random by uncommenting the 2nd line below
|
||||
//uint64_t seed = xxx;
|
||||
//rng::Seed<xoshio256ss> seed;
|
||||
|
||||
//auto rng = xo::rng::xoshiro256ss(seed);
|
||||
|
||||
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.dimension2"));
|
||||
//log && log("(A)", xtag("foo", foo));
|
||||
|
||||
using di = di_cartesian_product<typename gram::dim_type, typename second::dim_type>;
|
||||
|
||||
log && log(xtag("di", Reflect::require<di>()->canonical_name()));
|
||||
log && log(xtag("di::outer_scalefactor_type", Reflect::require<di::outer_scalefactor_type>()->canonical_name()));
|
||||
log && log(xtag("di::bpu_list_type", Reflect::require<di::bpu_list_type>()->canonical_name()));
|
||||
|
||||
using u1 = unit_cartesian_product_t<gram, second>;
|
||||
|
||||
log && log(xtag("u1", Reflect::require<u1>()->canonical_name()));
|
||||
|
||||
log && log(xtag("u1", ccs(unit_abbrev_v<u1>.value_)));
|
||||
} /*TEST_CASE(dimension2)*/
|
||||
|
||||
TEST_CASE("dimension3", "[dimension3]") {
|
||||
constexpr bool c_debug_flag = false;
|
||||
|
||||
// can get bits from /dev/random by uncommenting the 2nd line below
|
||||
//uint64_t seed = xxx;
|
||||
//rng::Seed<xoshio256ss> seed;
|
||||
|
||||
//auto rng = xo::rng::xoshiro256ss(seed);
|
||||
|
||||
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.dimension3"));
|
||||
//log && log("(A)", xtag("foo", foo));
|
||||
|
||||
using u1 = unit_invert_t<second>;
|
||||
|
||||
log && log(xtag("second^-1", Reflect::require<u1>()->canonical_name()));
|
||||
log && log(xtag("u1", unit_abbrev_v<u1>.c_str()));
|
||||
|
||||
REQUIRE(strcmp(unit_abbrev_v<u1>.c_str(), "s^-1") == 0);
|
||||
|
||||
using u2 = second;
|
||||
|
||||
log && log(xtag("second", Reflect::require<u2>()->canonical_name()));
|
||||
log && log(xtag("u2", unit_abbrev_v<u2>.c_str()));
|
||||
|
||||
using u1u2 = unit_cartesian_product_t<u1, u2>;
|
||||
|
||||
log && log(xtag("u1u2", Reflect::require<u1u2>()->canonical_name()));
|
||||
|
||||
#ifdef NOT_USING
|
||||
using di1 = d1::dim_type;
|
||||
using di2 = d2::dim_type;
|
||||
using di1di2 = di_cartesian_product<di1,di2>::type;
|
||||
|
||||
log && log(xtag("di1di2", Reflect::require<di1di2>()->canonical_name()));
|
||||
#endif
|
||||
|
||||
using f1 = u1::dim_type::front_type;
|
||||
using r1 = u1::dim_type::rest_type;
|
||||
using tmp = di_cartesian_product1<f1, r1, u2::dim_type>;
|
||||
|
||||
log && log(xtag("f1", Reflect::require<f1>()->canonical_name()));
|
||||
log && log(xtag("r1", Reflect::require<r1>()->canonical_name()));
|
||||
log && log(xtag("(f1.r1).outer_scalefactor_type", Reflect::require<tmp::outer_scalefactor_type>()->canonical_name()));
|
||||
log && log(xtag("(f1.r1).bpu_list_type", Reflect::require<tmp::bpu_list_type>()->canonical_name()));
|
||||
|
||||
using tmp2 = bpu_cartesian_product<f1, u2::dim_type>;
|
||||
|
||||
log && log(xtag("(f1.u2).outer_scalefactor_type", Reflect::require<tmp2::outer_scalefactor_type>()->canonical_name()));
|
||||
log && log(xtag("(f1.u2).bpu_list_type", Reflect::require<tmp2::bpu_list_type>()->canonical_name()));
|
||||
|
||||
using f2 = u2::dim_type::front_type;
|
||||
log && log(xtag("f2", Reflect::require<f2>()->canonical_name()));
|
||||
|
||||
using tmp3 = bpu_cartesian_product_helper<f1, f2, void>;
|
||||
log && log(xtag("(f1.f2).outer_scalefactor_type", Reflect::require<tmp3::outer_scalefactor_type>()->canonical_name()));
|
||||
log && log(xtag("(f1.f2).bpu_list_type", Reflect::require<tmp3::bpu_list_type>()->canonical_name()));
|
||||
} /*TEST_CASE(dimension3)*/
|
||||
|
||||
|
||||
} /*namespace ut*/
|
||||
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/* end dimension.test.cpp */
|
||||
422
xo-unit/utest/natural_unit.test.cpp
Normal file
422
xo-unit/utest/natural_unit.test.cpp
Normal file
|
|
@ -0,0 +1,422 @@
|
|||
/* @file natural_unit.test.cpp */
|
||||
|
||||
#include "xo/unit/scaled_unit.hpp"
|
||||
#include "xo/unit/scaled_unit_iostream.hpp"
|
||||
#include "xo/unit/natural_unit.hpp"
|
||||
#include "xo/indentlog/scope.hpp"
|
||||
#include "xo/indentlog/print/tag.hpp"
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
namespace xo {
|
||||
using xo::qty::detail::su_product;
|
||||
using xo::qty::detail::su_ratio;
|
||||
using xo::qty::detail::nu_ratio_inplace;
|
||||
using xo::qty::detail::nu_maker;
|
||||
using xo::qty::detail::bpu2_rescale; // -> nu_rescale or bpu_rescale
|
||||
|
||||
namespace qty {
|
||||
using nu64_type = natural_unit<std::int64_t>;
|
||||
|
||||
/* compile-time test:
|
||||
* verify we can use an nu64_type instance as a non-type template parameter.
|
||||
* Will need this for quantity<Repr, Int, natural_unit<Int>>
|
||||
*/
|
||||
template <nu64_type nu>
|
||||
constexpr nu_abbrev_type nu_mpl_abbrev = nu.abbrev();
|
||||
|
||||
TEST_CASE("natural_unit0", "[natural_unit]") {
|
||||
constexpr bool c_debug_flag = false;
|
||||
|
||||
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.natural_unit0"));
|
||||
|
||||
{
|
||||
constexpr natural_unit<int64_t> v
|
||||
= (nu_maker<int64_t>::make_nu
|
||||
(bpu<int64_t>(dim::distance, scalefactor_ratio_type(1, 1000), power_ratio_type(2, 1)),
|
||||
bpu<int64_t>(dim::mass, scalefactor_ratio_type(1, 1000), power_ratio_type(-1, 1))));
|
||||
|
||||
static_assert(v.n_bpu() == 2);
|
||||
|
||||
log && log(xtag("v.abbrev", v.abbrev()));
|
||||
|
||||
static_assert(v.abbrev().size() > 0);
|
||||
static_assert(v.abbrev() == flatstring("mm^2.mg^-1"));
|
||||
}
|
||||
} /*TEST_CASE(natural_unit0)*/
|
||||
|
||||
TEST_CASE("natural_unit1", "[natural_unit]") {
|
||||
constexpr bool c_debug_flag = false;
|
||||
|
||||
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.natural_unit1"));
|
||||
|
||||
{
|
||||
constexpr natural_unit<int64_t> v
|
||||
= (nu_maker<int64_t>::make_nu
|
||||
(bpu<int64_t>(dim::distance, scalefactor_ratio_type(1000, 1), power_ratio_type(2, 1))));
|
||||
|
||||
static_assert(v.n_bpu() == 1);
|
||||
|
||||
log && log(xtag("v.abbrev", v.abbrev()));
|
||||
|
||||
static_assert(v.abbrev().size() > 0);
|
||||
static_assert(v.abbrev() == flatstring("km^2"));
|
||||
}
|
||||
} /*TEST_CASE(natural_unit1)*/
|
||||
|
||||
TEST_CASE("natural_unit2", "[natural_unit]") {
|
||||
constexpr bool c_debug_flag = false;
|
||||
|
||||
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.natural_unit2"));
|
||||
|
||||
{
|
||||
constexpr natural_unit<int64_t> v
|
||||
= (nu_maker<int64_t>::make_nu
|
||||
(bpu<int64_t>(dim::mass, scalefactor_ratio_type(1000, 1), power_ratio_type(1, 1)),
|
||||
bpu<int64_t>(dim::distance, scalefactor_ratio_type(1, 1), power_ratio_type(1, 1)),
|
||||
bpu<int64_t>(dim::time, scalefactor_ratio_type(1, 1), power_ratio_type(-2, 1))));
|
||||
|
||||
static_assert(v.n_bpu() == 3);
|
||||
|
||||
log && log(xtag("v.abbrev", v.abbrev()));
|
||||
|
||||
static_assert(v.abbrev().size() > 0);
|
||||
static_assert(v.abbrev() == flatstring("kg.m.s^-2"));
|
||||
}
|
||||
} /*TEST_CASE(natural_unit2)*/
|
||||
|
||||
TEST_CASE("natural_unit3", "[natural_unit]") {
|
||||
constexpr bool c_debug_flag = false;
|
||||
|
||||
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.natural_unit3"));
|
||||
|
||||
{
|
||||
constexpr natural_unit<int64_t> v
|
||||
= (nu_maker<int64_t>::make_nu
|
||||
(bpu<int64_t>(dim::mass, scalefactor_ratio_type(1000, 1), power_ratio_type(1, 1)),
|
||||
bpu<int64_t>(dim::distance, scalefactor_ratio_type(1, 1), power_ratio_type(1, 1))));
|
||||
|
||||
static_assert(v.n_bpu() == 2);
|
||||
|
||||
log && log(xtag("v.abbrev", v.abbrev()));
|
||||
|
||||
static_assert(v.abbrev().size() > 0);
|
||||
static_assert(v.abbrev() == flatstring("kg.m"));
|
||||
|
||||
{
|
||||
natural_unit<int64_t> w = v;
|
||||
|
||||
nu_ratio_inplace(&w,
|
||||
bpu<int64_t>(dim::mass, scalefactor_ratio_type(1000, 1), power_ratio_type(1, 1)));
|
||||
|
||||
log && log(xtag("w.abbrev", w.abbrev()));
|
||||
|
||||
REQUIRE(w.n_bpu() == 1);
|
||||
REQUIRE(w[0].native_dim() == dim::distance);
|
||||
REQUIRE(w.abbrev() == flatstring("m"));
|
||||
}
|
||||
|
||||
{
|
||||
constexpr natural_unit<int64_t> w
|
||||
= (nu_maker<int64_t>::make_nu
|
||||
(bpu<int64_t>(dim::mass, scalefactor_ratio_type(1000, 1), power_ratio_type(1, 1))));
|
||||
|
||||
static_assert(w.n_bpu() == 1);
|
||||
|
||||
log && log(xtag("w.abbrev", w.abbrev()));
|
||||
|
||||
constexpr auto rr = su_ratio<int64_t, __int128_t>(v, w);
|
||||
|
||||
log && log(xtag("rr", rr));
|
||||
|
||||
REQUIRE(rr.natural_unit_.n_bpu() == 1);
|
||||
REQUIRE(rr.natural_unit_[0].native_dim() == dim::distance);
|
||||
REQUIRE(rr.natural_unit_.abbrev() == flatstring("m"));
|
||||
}
|
||||
|
||||
{
|
||||
constexpr natural_unit<int64_t> w
|
||||
= (nu_maker<int64_t>::make_nu
|
||||
(bpu<int64_t>(dim::time, scalefactor_ratio_type(1, 1), power_ratio_type(1, 1))));
|
||||
|
||||
static_assert(w.n_bpu() == 1);
|
||||
|
||||
log && log(xtag("w.abbrev", w.abbrev()));
|
||||
|
||||
constexpr auto rr = su_ratio<int64_t, __int128_t>(v, w);
|
||||
|
||||
log && log(xtag("rr", rr));
|
||||
|
||||
REQUIRE(rr.natural_unit_.n_bpu() == 3);
|
||||
REQUIRE(rr.natural_unit_[0].native_dim() == dim::mass);
|
||||
REQUIRE(rr.natural_unit_[1].native_dim() == dim::distance);
|
||||
REQUIRE(rr.natural_unit_[2].native_dim() == dim::time);
|
||||
REQUIRE(rr.natural_unit_.abbrev() == flatstring("kg.m.s^-1"));
|
||||
}
|
||||
|
||||
{
|
||||
natural_unit<int64_t> w = v;
|
||||
|
||||
REQUIRE(w.n_bpu() == 2);
|
||||
REQUIRE(w[0].native_dim() == dim::mass);
|
||||
|
||||
nu_ratio_inplace(&w,
|
||||
bpu<int64_t>(dim::time, scalefactor_ratio_type(1, 1), power_ratio_type(2, 1)));
|
||||
|
||||
REQUIRE(w.n_bpu() == 3);
|
||||
REQUIRE(w[0].native_dim() == dim::mass);
|
||||
REQUIRE(w[1].native_dim() == dim::distance);
|
||||
REQUIRE(w[2].native_dim() == dim::time);
|
||||
|
||||
log && log(xtag("w.abbrev", w.abbrev()));
|
||||
|
||||
REQUIRE(w.n_bpu() == 3);
|
||||
REQUIRE(w.abbrev() == flatstring("kg.m.s^-2"));
|
||||
}
|
||||
}
|
||||
} /*TEST_CASE(natural_unit3)*/
|
||||
|
||||
TEST_CASE("bpu_rescale", "[bpu_rescale]") {
|
||||
constexpr bool c_debug_flag = false;
|
||||
|
||||
// can get bits from /dev/random by uncommenting the 2nd line below
|
||||
//uint64_t seed = xxx;
|
||||
//rng::Seed<xoshio256ss> seed;
|
||||
|
||||
//auto rng = xo::rng::xoshiro256ss(seed);
|
||||
|
||||
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.bpu_rescale"));
|
||||
//log && log("(A)", xtag("foo", foo));
|
||||
|
||||
/* keep spelled-out test. Will generalize to fractional powers when c++26 available */
|
||||
{
|
||||
constexpr auto p = power_ratio_type(1, 1);
|
||||
|
||||
constexpr auto orig_bpu = bpu<int64_t>(dim::mass,
|
||||
scalefactor_ratio_type(1000, 1),
|
||||
power_ratio_type(1, 1));
|
||||
static_assert(orig_bpu.native_dim() == dim::mass);
|
||||
|
||||
constexpr auto new_scalefactor = scalefactor_ratio_type(1000000, 1);
|
||||
|
||||
constexpr auto mult = orig_bpu.scalefactor() / new_scalefactor;
|
||||
static_assert(mult.num() == 1);
|
||||
static_assert(mult.den() == 1000);
|
||||
|
||||
constexpr auto p_floor = orig_bpu.power().floor();
|
||||
static_assert(p_floor == 1);
|
||||
|
||||
constexpr auto p_frac = orig_bpu.power().frac().template convert_to<double>();
|
||||
static_assert(p_frac == 0.0);
|
||||
|
||||
constexpr auto outer_sf_exact = mult.power(p_floor);
|
||||
static_assert(outer_sf_exact.num() == 1);
|
||||
static_assert(outer_sf_exact.den() == 1000);
|
||||
|
||||
constexpr auto mult_inexact = mult.template convert_to<double>();
|
||||
static_assert(mult_inexact == 0.001);
|
||||
|
||||
constexpr auto rr = bpu2_rescale<int64_t>(orig_bpu, scalefactor_ratio_type(1000000, 1));
|
||||
|
||||
static_assert(rr.bpu_rescaled_.power() == power_ratio_type(1,1));
|
||||
static_assert(rr.outer_scale_factor_ == outer_sf_exact);
|
||||
static_assert(rr.outer_scale_sq_ == 1.0);
|
||||
}
|
||||
|
||||
/* keep spelled-out test. Will generalize to other fractional powers when c++26 available */
|
||||
{
|
||||
constexpr auto p = power_ratio_type(-1, 2);
|
||||
|
||||
constexpr auto orig_bpu = bpu<int64_t>(dim::time,
|
||||
scalefactor_ratio_type(360*24*3600, 1),
|
||||
power_ratio_type(-1, 2));
|
||||
static_assert(orig_bpu.native_dim() == dim::time);
|
||||
|
||||
constexpr auto new_scalefactor = scalefactor_ratio_type(30*24*3600, 1);
|
||||
|
||||
/* orig ~ 360d volatility, new = 30d volatility */
|
||||
constexpr auto mult = orig_bpu.scalefactor() / new_scalefactor;
|
||||
log && log(xtag("mult", mult));
|
||||
static_assert(mult.num() == 12);
|
||||
static_assert(mult.den() == 1);
|
||||
|
||||
constexpr auto p_floor = orig_bpu.power().floor();
|
||||
static_assert(p_floor == 0);
|
||||
|
||||
constexpr auto p_frac = orig_bpu.power().frac().template convert_to<double>();
|
||||
static_assert(p_frac == -0.5);
|
||||
|
||||
constexpr auto outer_sf_exact = mult.power(p_floor);
|
||||
static_assert(outer_sf_exact.num() == 1);
|
||||
static_assert(outer_sf_exact.den() == 1);
|
||||
|
||||
constexpr auto mult_inexact = mult.template convert_to<double>();
|
||||
static_assert(mult_inexact == 12.0);
|
||||
|
||||
constexpr auto rr = bpu2_rescale<int64_t>(orig_bpu, scalefactor_ratio_type(30*24*3600, 1));
|
||||
|
||||
log && log(xtag("rr.outer_scale_exact", rr.outer_scale_factor_),
|
||||
xtag("rr.outer_scale_sq", rr.outer_scale_sq_));
|
||||
|
||||
static_assert(rr.bpu_rescaled_.power() == power_ratio_type(-1,2));
|
||||
static_assert(rr.outer_scale_factor_ == outer_sf_exact);
|
||||
static_assert(rr.outer_scale_sq_ == 1 / 12.0);
|
||||
}
|
||||
|
||||
/* keep spelled-out test. Will generalize to other fractional powers when c++26 available */
|
||||
{
|
||||
constexpr auto p = power_ratio_type(-3, 2);
|
||||
|
||||
constexpr auto orig_bpu = bpu<int64_t>(dim::time,
|
||||
scalefactor_ratio_type(360*24*3600, 1),
|
||||
power_ratio_type(-3, 2));
|
||||
static_assert(orig_bpu.native_dim() == dim::time);
|
||||
|
||||
constexpr auto new_scalefactor = scalefactor_ratio_type(30*24*3600, 1);
|
||||
|
||||
constexpr auto mult = orig_bpu.scalefactor() / new_scalefactor;
|
||||
log && log(xtag("mult", mult));
|
||||
static_assert(mult.num() == 12);
|
||||
static_assert(mult.den() == 1);
|
||||
|
||||
constexpr auto p_floor = orig_bpu.power().floor();
|
||||
static_assert(p_floor == -1);
|
||||
|
||||
constexpr auto p_frac = orig_bpu.power().frac().template convert_to<double>();
|
||||
static_assert(p_frac == -0.5);
|
||||
|
||||
constexpr auto outer_sf_exact = mult.power(p_floor);
|
||||
static_assert(outer_sf_exact.num() == 1);
|
||||
static_assert(outer_sf_exact.den() == 12);
|
||||
|
||||
constexpr auto mult_inexact = mult.template convert_to<double>();
|
||||
static_assert(mult_inexact == 12.0);
|
||||
|
||||
constexpr auto rr = bpu2_rescale<int64_t>(orig_bpu, scalefactor_ratio_type(30*24*3600, 1));
|
||||
|
||||
log && log(xtag("rr.outer_scale_exact", rr.outer_scale_factor_),
|
||||
xtag("rr.outer_scale_sq", rr.outer_scale_sq_));
|
||||
|
||||
static_assert(rr.bpu_rescaled_.power() == power_ratio_type(-3,2));
|
||||
static_assert(rr.outer_scale_factor_ == outer_sf_exact);
|
||||
static_assert(rr.outer_scale_sq_ == 1 / 12.0);
|
||||
}
|
||||
} /*TEST_CASE(bpu_rescale)*/
|
||||
|
||||
TEST_CASE("bpu_product", "[bpu_product]") {
|
||||
constexpr bool c_debug_flag = false;
|
||||
|
||||
// can get bits from /dev/random by uncommenting the 2nd line below
|
||||
//uint64_t seed = xxx;
|
||||
//rng::Seed<xoshio256ss> seed;
|
||||
|
||||
//auto rng = xo::rng::xoshiro256ss(seed);
|
||||
|
||||
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.bpu_product"));
|
||||
//log && log("(A)", xtag("foo", foo));
|
||||
|
||||
{
|
||||
constexpr auto bpu_x = bpu<int64_t>(dim::time,
|
||||
scalefactor_ratio_type(360*24*3600, 1),
|
||||
power_ratio_type(-3,2));
|
||||
static_assert(bpu_x.native_dim() == dim::time);
|
||||
|
||||
constexpr auto bpu_y = bpu<int64_t>(dim::time,
|
||||
scalefactor_ratio_type(360*24*3600, 1),
|
||||
power_ratio_type(1,2));
|
||||
static_assert(bpu_y.native_dim() == dim::time);
|
||||
|
||||
#ifdef NOT_USING
|
||||
constexpr auto bpu_prod = bpu2_product<int64_t>(bpu_x, bpu_y);
|
||||
|
||||
log && log(xtag("bpu_prod.bpu_rescaled", bpu_prod.bpu_rescaled_));
|
||||
log && log(xtag("bpu_prod.outer_scale_exact", bpu_prod.outer_scale_exact_));
|
||||
log && log(xtag("bpu_prod.outer_scale_sq", bpu_prod.outer_scale_sq_));
|
||||
|
||||
static_assert(bpu_prod.bpu_rescaled_.native_dim() == dim::time);
|
||||
static_assert(bpu_prod.bpu_rescaled_.scalefactor() == scalefactor_ratio_type(360*24*3600, 1));
|
||||
static_assert(bpu_prod.bpu_rescaled_.power() == power_ratio_type(-1, 1));
|
||||
static_assert(bpu_prod.outer_scale_exact_ == scalefactor_ratio_type(1,1));
|
||||
static_assert(bpu_prod.outer_scale_sq_ == 1.0);
|
||||
#endif
|
||||
}
|
||||
} /*TEST_CASE(bpu_product)*/
|
||||
|
||||
TEST_CASE("bpu_product2", "[bpu_product]") {
|
||||
constexpr bool c_debug_flag = false;
|
||||
|
||||
// can get bits from /dev/random by uncommenting the 2nd line below
|
||||
//uint64_t seed = xxx;
|
||||
//rng::Seed<xoshio256ss> seed;
|
||||
|
||||
//auto rng = xo::rng::xoshiro256ss(seed);
|
||||
|
||||
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.bpu_product2"));
|
||||
//log && log("(A)", xtag("foo", foo));
|
||||
|
||||
{
|
||||
constexpr auto bpu_x = bpu<int64_t>(dim::time,
|
||||
scalefactor_ratio_type(360*24*3600, 1),
|
||||
power_ratio_type(-3,2));
|
||||
static_assert(bpu_x.native_dim() == dim::time);
|
||||
|
||||
constexpr auto bpu_y = bpu<int64_t>(dim::time,
|
||||
scalefactor_ratio_type(30*24*3600, 1),
|
||||
power_ratio_type(1,2));
|
||||
static_assert(bpu_y.native_dim() == dim::time);
|
||||
|
||||
#ifdef NOT_USING
|
||||
constexpr auto bpu_prod = bpu2_product<int64_t>(bpu_x, bpu_y);
|
||||
|
||||
log && log(xtag("bpu_prod.bpu_rescaled", bpu_prod.bpu_rescaled_));
|
||||
log && log(xtag("bpu_prod.outer_scale_exact", bpu_prod.outer_scale_exact_));
|
||||
log && log(xtag("bpu_prod.outer_scale_sq", bpu_prod.outer_scale_sq_));
|
||||
|
||||
static_assert(bpu_prod.bpu_rescaled_.native_dim() == dim::time);
|
||||
static_assert(bpu_prod.bpu_rescaled_.scalefactor() == scalefactor_ratio_type(360*24*3600, 1));
|
||||
static_assert(bpu_prod.bpu_rescaled_.power() == power_ratio_type(-1, 1));
|
||||
static_assert(bpu_prod.outer_scale_exact_ == scalefactor_ratio_type(1,1));
|
||||
static_assert(bpu_prod.outer_scale_sq_ == 1.0/12.0);
|
||||
#endif
|
||||
}
|
||||
} /*TEST_CASE(bpu_product2)*/
|
||||
|
||||
TEST_CASE("bpu_array", "[bpu_array]") {
|
||||
constexpr bool c_debug_flag = false;
|
||||
|
||||
// can get bits from /dev/random by uncommenting the 2nd line below
|
||||
//uint64_t seed = xxx;
|
||||
//rng::Seed<xoshio256ss> seed;
|
||||
|
||||
//auto rng = xo::rng::xoshiro256ss(seed);
|
||||
|
||||
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.bpu_array"));
|
||||
//log && log("(A)", xtag("foo", foo));
|
||||
|
||||
{
|
||||
constexpr natural_unit<int64_t> v;
|
||||
|
||||
static_assert(v.n_bpu() == 0);
|
||||
}
|
||||
|
||||
{
|
||||
constexpr natural_unit<int64_t> v
|
||||
= (nu_maker<int64_t>::make_nu
|
||||
(bpu<int64_t>(dim::mass, scalefactor_ratio_type(1000, 1), power_ratio_type(1, 1))));
|
||||
|
||||
static_assert(v.n_bpu() == 1);
|
||||
}
|
||||
|
||||
{
|
||||
constexpr natural_unit<int64_t> v
|
||||
= (nu_maker<int64_t>::make_nu
|
||||
(bpu<int64_t>(dim::distance, scalefactor_ratio_type(1, 1000), power_ratio_type(2, 1)),
|
||||
bpu<int64_t>(dim::mass, scalefactor_ratio_type(1, 1000), power_ratio_type(-1, 1))));
|
||||
|
||||
static_assert(v.n_bpu() == 2);
|
||||
}
|
||||
} /*TEST_CASE(bpu_array)*/
|
||||
} /*namespace qty*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/* end natural_unit.test.cpp */
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue