This commit is contained in:
Mateusz Pusz
2020-09-06 15:38:18 +02:00
38 changed files with 609 additions and 189 deletions

3
.gitmodules vendored
View File

@@ -1,3 +0,0 @@
[submodule "cmake/common"]
path = cmake/common
url = https://github.com/mpusz/cmake-scripts.git

View File

@@ -27,7 +27,7 @@ project(mp-units)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
# include common tools and workarounds
include(common/cmake/scripts)
include(common/scripts)
# use Conan configuration if available
conan_init(cmake)
@@ -40,7 +40,7 @@ conan_init(cmake)
add_subdirectory(src)
# set restrictive compilation warnings
set_warnings(units)
set_warnings(mp-units)
# add unit tests
enable_testing()

View File

@@ -9,7 +9,6 @@ if __name__ == "__main__":
# dependencies
remotes = [
("https://api.bintray.com/conan/bincrafters/public-conan", True, "bincrafters"),
("https://api.bintray.com/conan/twonington/public-conan", True, "linear-algebra")
],
build_policy = ["mp-units", "outdated"],

Submodule cmake/common deleted from eb5fbd40d1

46
cmake/common/conan.cmake Normal file
View File

@@ -0,0 +1,46 @@
# The MIT License (MIT)
#
# Copyright (c) 2017 Mateusz Pusz
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# Helper to use conan generated configuration if provided
macro(conan_init generator)
if(${generator} STREQUAL "cmake_paths")
include(${CMAKE_BINARY_DIR}/conan_paths.cmake OPTIONAL)
elseif(${generator} STREQUAL "cmake")
if(NOT DEFINED CONAN_PACKAGE_NAME)
if(EXISTS ${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup(TARGETS)
endif()
endif()
else()
message(FATAL_ERROR "Unknown Conan generator: ${generator}")
endif()
endmacro()
# Checks if conan installed testing dependencies
macro(conan_check_testing test_framework)
if(NOT TARGET CONAN_PKG::${test_framework})
message(FATAL_ERROR "CONAN_PKG::${test_framework} not found!\nPlease run `conan install` with `-e CONAN_RUN_TESTS=True`.")
endif()
endmacro()

View File

@@ -0,0 +1,81 @@
# The MIT License (MIT)
#
# Copyright (c) 2017 Mateusz Pusz
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# A path to scripts directory
set(CMAKE_SCRIPTS_ROOT ${CMAKE_CURRENT_LIST_DIR})
# Install provided targets
function(install_targets)
if(NOT CMAKE_INSTALL_BINDIR)
set(CMAKE_INSTALL_BINDIR "bin")
endif()
if(NOT CMAKE_INSTALL_LIBDIR)
set(CMAKE_INSTALL_LIBDIR "lib")
endif()
if(NOT CMAKE_INSTALL_INCLUDEDIR)
set(CMAKE_INSTALL_INCLUDEDIR "include")
endif()
install(TARGETS ${ARGN}
EXPORT ${PROJECT_NAME}Targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} # TODO Remove when CMAKE 3.14
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} # TODO Remove when CMAKE 3.14
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} # TODO Remove when CMAKE 3.14
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
endfunction()
# Generate configuration files and install the package
function(configure_and_install configure_in_file_path namespace version_compare_rules)
if(NOT APPLE)
set(CMAKE_INSTALL_RPATH ${ORIGIN})
endif()
# prepare installation files
include(CMakePackageConfigHelpers)
set(ConfigPackageSource ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME})
set(ConfigPackageDestination lib/cmake/${PROJECT_NAME})
write_basic_package_version_file(
${ConfigPackageSource}/${PROJECT_NAME}-config-version.cmake
COMPATIBILITY ${version_compare_rules})
configure_package_config_file(${configure_in_file_path}
${ConfigPackageSource}/${PROJECT_NAME}-config.cmake
INSTALL_DESTINATION ${ConfigPackageDestination})
# install library
install(EXPORT ${PROJECT_NAME}Targets
DESTINATION ${ConfigPackageDestination}
FILE ${PROJECT_NAME}-targets.cmake
NAMESPACE ${namespace}::
COMPONENT Devel)
install(FILES
"${ConfigPackageSource}/${PROJECT_NAME}-config.cmake"
"${ConfigPackageSource}/${PROJECT_NAME}-config-version.cmake"
DESTINATION ${ConfigPackageDestination}
COMPONENT Devel)
# local package
export(EXPORT ${PROJECT_NAME}Targets
NAMESPACE ${namespace}::
FILE ${ConfigPackageSource}/${PROJECT_NAME}-targets.cmake)
endfunction()

View File

@@ -0,0 +1,28 @@
# The MIT License (MIT)
#
# Copyright (c) 2017 Mateusz Pusz
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
include(conan)
include(install)
include(static_analysis)
include(warnings)

View File

@@ -0,0 +1 @@
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake")

View File

@@ -0,0 +1,44 @@
# The MIT License (MIT)
#
# Copyright (c) 2017 Mateusz Pusz
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
macro(enable_clang_tidy)
find_program(clang_tidy_cmd NAMES "clang-tidy")
if(NOT clang_tidy_cmd)
message(WARNING "clang-tidy not found!")
else()
if(NOT EXISTS "${CMAKE_SOURCE_DIR}/.clang-tidy")
message(FATAL_ERROR "'${CMAKE_SOURCE_DIR}/.clang-tidy' configuration file not found!")
endif()
set(CMAKE_CXX_CLANG_TIDY "${clang_tidy_cmd}")
endif()
endmacro()
macro(enable_iwyu)
find_program(iwyu_cmd NAMES "include-what-you-use")
if(NOT iwyu_cmd)
message(WARNING "include-what-you-use not found!")
else()
set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE "${iwyu_cmd}")
endif()
endmacro()

110
cmake/common/warnings.cmake Normal file
View File

@@ -0,0 +1,110 @@
# The MIT License (MIT)
#
# Copyright (c) 2016 Mateusz Pusz
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# Based on https://github.com/lefticus/cpp_starter_project/blob/master/cmake/CompilerWarnings.cmake
# Configure compiler warning level
function(set_warnings target)
option(WARNINGS_AS_ERRORS "Treat compiler warnings as errors" TRUE)
if(NOT TARGET ${target})
message(FATAL_ERROR "'${target}' is not a CMake target")
endif()
set(MSVC_WARNINGS
/W4 # Baseline reasonable warnings
/w14062 # enumerator 'identifier' in a switch of enum 'enumeration' is not handled
/w14242 # 'identifier': conversion from 'type1' to 'type1', possible loss of data
/w14254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data
/w14263 # 'function': member function does not override any base class virtual member function
/w14265 # 'classname': class has virtual functions, but destructor is not
# virtual instances of this class may not be destructed correctly
/w14266 # 'function': no override available for virtual member function from base 'type'; function is hidden
/w14287 # 'operator': unsigned/negative constant mismatch
/we4289 # nonstandard extension used: 'variable': loop control variable
# declared in the for-loop is used outside the for-loop scope
/w14296 # 'operator': expression is always 'boolean_value'
/w14311 # 'variable': pointer truncation from 'type1' to 'type2'
/w14545 # expression before comma evaluates to a function which is missing
# an argument list
/w14546 # function call before comma missing argument list
/w14547 # 'operator': operator before comma has no effect; expected
# operator with side-effect
/w14549 # 'operator': operator before comma has no effect; did you intend
# 'operator'?
/w14555 # expression has no effect; expected expression with side- effect
/w14619 # pragma warning: there is no warning number 'number'
/w14640 # Enable warning on thread un-safe static member initialization
/w14826 # Conversion from 'type1' to 'type_2' is sign-extended. This may
# cause unexpected runtime behavior.
/w14905 # wide string literal cast to 'LPSTR'
/w14906 # string literal cast to 'LPWSTR'
/w14928 # illegal copy-initialization; more than one user-defined
# conversion has been implicitly applied
/permissive- # standards conformance mode for MSVC compiler.
)
set(CLANG_WARNINGS
-Wall
-Wextra # reasonable and standard
-Wpedantic # warn if non-standard C++ is used
-Wshadow # warn the user if a variable declaration shadows one from a parent context
-Wnon-virtual-dtor # warn the user if a class with virtual functions has a
# non-virtual destructor. This helps catch hard to
# track down memory errors
-Wold-style-cast # warn for c-style casts
-Wcast-align # warn for potential performance problem casts
-Wunused # warn on anything being unused
-Woverloaded-virtual # warn if you overload (not override) a virtual function
-Wcast-qual # warn on dropping const or volatile qualifiers
-Wconversion # warn on type conversions that may lose data
-Wsign-conversion # warn on sign conversions
-Wnull-dereference # warn if a null dereference is detected
-Wdouble-promotion # warn if float is implicit promoted to double
-Wformat=2 # warn on security issues around functions that format output (ie printf)
)
if(WARNINGS_AS_ERRORS)
set(CLANG_WARNINGS ${CLANG_WARNINGS} -Werror)
set(MSVC_WARNINGS ${MSVC_WARNINGS} /WX)
endif()
set(GCC_WARNINGS
${CLANG_WARNINGS}
-Wmisleading-indentation # warn if indentation implies blocks where blocks do not exist
-Wduplicated-cond # warn if if / else chain has duplicated conditions
-Wduplicated-branches # warn if if / else branches have duplicated code
-Wlogical-op # warn about logical operations being used where bitwise were probably wanted
)
if(MSVC)
string(REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" PARENT_SCOPE)
target_compile_options(${target} INTERFACE ${MSVC_WARNINGS})
elseif(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang")
target_compile_options(${target} INTERFACE ${CLANG_WARNINGS})
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
target_compile_options(${target} INTERFACE ${GCC_WARNINGS})
else()
message(AUTHOR_WARNING "No compiler warnings set for '${CMAKE_CXX_COMPILER_ID}' compiler.")
endif()
endfunction()

View File

@@ -21,7 +21,7 @@
# SOFTWARE.
from conans import ConanFile, CMake, tools
from conans.tools import Version
from conans.tools import Version, check_min_cppstd
from conans.errors import ConanInvalidConfiguration
import re
@@ -38,17 +38,18 @@ def get_version():
class UnitsConan(ConanFile):
name = "mp-units"
version = get_version()
author = "Mateusz Pusz"
license = "https://github.com/mpusz/units/blob/master/LICENSE.md"
url = "https://github.com/mpusz/units"
homepage = "https://github.com/mpusz/units"
description = "Physical Units library for C++"
exports = ["LICENSE.md"]
exports_sources = ["docs/*", "src/*", "test/*", "cmake/*", "example/*","CMakeLists.txt"]
topics = ("units", "dimensions", "quantities", "dimensional-analysis", "physical-quantities", "physical-units", "system-of-units", "cpp23", "cpp20", "library", "quantity-manipulation")
license = "MIT"
url = "https://github.com/mpusz/units"
settings = "os", "compiler", "build_type", "arch"
requires = (
"fmt/7.0.3",
"ms-gsl/3.1.0"
)
exports = ["LICENSE.md"]
exports_sources = ["docs/*", "src/*", "test/*", "cmake/*", "example/*","CMakeLists.txt"]
# scm = {
# "type": "git",
# "url": "auto",
@@ -61,6 +62,19 @@ class UnitsConan(ConanFile):
def _run_tests(self):
return tools.get_env("CONAN_RUN_TESTS", False)
def _validate_compiler_settings(self):
compiler = self.settings.compiler
version = Version(self.settings.compiler.version)
if compiler == "gcc":
if version < "9.3":
raise ConanInvalidConfiguration("mp-units requires at least g++-9.3")
elif compiler == "Visual Studio":
if version < "16":
raise ConanInvalidConfiguration("mp-units requires at least MSVC 16")
else:
raise ConanInvalidConfiguration("mp-units is supported only by gcc and Visual Studio so far")
check_min_cppstd(self, "20")
def _configure_cmake(self, folder="src"):
cmake = CMake(self)
if self._run_tests:
@@ -72,15 +86,7 @@ class UnitsConan(ConanFile):
return cmake
def configure(self):
if self.settings.compiler != "gcc" and self.settings.compiler != "Visual Studio": # and self.settings.compiler != "clang":
raise ConanInvalidConfiguration("Library works only with gcc and Visual Studio so far") # and clang")
if self.settings.compiler == "gcc" and Version(self.settings.compiler.version) < "9":
raise ConanInvalidConfiguration("Library requires at least g++-9")
if self.settings.compiler == "Visual Studio" and Version(self.settings.compiler.version) < "16":
raise ConanInvalidConfiguration("Library requires at least Visual Studio 2019")
if self.settings.compiler == "clang" and Version(self.settings.compiler.version) < "11":
raise ConanInvalidConfiguration("Library requires at least clang++-11")
tools.check_min_cppstd(self, "20")
self._validate_compiler_settings()
def requirements(self):
if ((self.settings.compiler == "gcc" and Version(self.settings.compiler.version) < "10") or
@@ -104,18 +110,25 @@ class UnitsConan(ConanFile):
cmake = self._configure_cmake()
cmake.install()
def package_info(self):
if self.settings.compiler == "gcc":
self.cpp_info.cxxflags = [
"-Wno-literal-suffix",
"-Wno-non-template-friend",
]
if Version(self.settings.compiler.version) < "10":
self.cpp_info.cxxflags.extend([
"-fconcepts"
])
def package_id(self):
self.info.settings.clear()
self.info.settings.compiler = self.settings.compiler
self.info.settings.compiler.version = self.settings.compiler.version
def package_info(self):
compiler = self.settings.compiler
version = Version(self.settings.compiler.version)
if compiler == "gcc":
self.cpp_info.cxxflags = [
"-Wno-literal-suffix",
"-Wno-non-template-friend",
]
if version < "10":
self.cpp_info.cxxflags.extend([
"-fconcepts"
])
elif compiler == "Visual Studio":
self.cpp_info.cxxflags = [
"/utf-8",
"/wd4455"
]

View File

@@ -8,6 +8,7 @@
- catch2 updated to 2.13.0
- doxygen updated to 1.8.18
- ms-gsl 3.1.0 dependency added
- MSVC 16.7 support added
- Added angle as SI base dimension (thanks [@kwikius](https://github.com/kwikius))
- Added STL random number distribution wrappers (thanks [@yasamoka](https://github.com/yasamoka))
- `math.h` function signatures refactored to use a `Quantity` concept (thanks [@kwikius](https://github.com/kwikius))

View File

@@ -20,6 +20,8 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
cmake_minimum_required(VERSION 3.12)
option(GENERATE_DOCS "Generate project documenation" ON)
if(NOT GENERATE_DOCS)
return()

View File

@@ -80,7 +80,7 @@ in *~/.conan/profile* directory. An example profile can look as follows:
arch=x86_64
arch_build=x86_64
compiler=gcc
compiler.version=9
compiler.version=10
compiler.cppstd=20
compiler.libcxx=libstdc++11
build_type=Release
@@ -89,8 +89,8 @@ in *~/.conan/profile* directory. An example profile can look as follows:
[build_requires]
[env]
CC=/usr/bin/gcc-9
CXX=/usr/bin/g++-9
CC=/usr/bin/gcc-10
CXX=/usr/bin/g++-10
.. tip::

View File

@@ -20,9 +20,11 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
cmake_minimum_required(VERSION 3.12)
function(add_example target)
add_executable(${target} ${target}.cpp)
target_link_libraries(${target} PRIVATE mp::units)
target_link_libraries(${target} PRIVATE mp-units::mp-units)
endfunction()
add_example(box_example)

View File

@@ -20,9 +20,11 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
cmake_minimum_required(VERSION 3.12)
function(add_example target)
add_executable(${target}_alt ${target}.cpp)
target_link_libraries(${target}_alt PRIVATE mp::units)
target_link_libraries(${target}_alt PRIVATE mp-units::mp-units)
endfunction()
add_example(box_example)

View File

@@ -31,14 +31,14 @@ project(mp-units
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../cmake")
# include common tools and workarounds
include(common/cmake/scripts)
include(common/scripts)
# use Conan configuration if available
conan_init(cmake)
# library definition
add_library(units INTERFACE)
#target_sources(units INTERFACE
add_library(mp-units INTERFACE)
#target_sources(mp-units INTERFACE
# include/units/dimension.h
# include/units/quantity.h
# include/units/unit.h
@@ -52,55 +52,55 @@ add_library(units INTERFACE)
# include/units/si/time.h
# include/units/si/speed.h
#)
target_compile_features(units INTERFACE cxx_std_20)
target_link_libraries(units
target_compile_features(mp-units INTERFACE cxx_std_20)
target_link_libraries(mp-units
INTERFACE
$<IF:$<TARGET_EXISTS:CONAN_PKG::fmt>,CONAN_PKG::fmt,fmt::fmt>
$<IF:$<TARGET_EXISTS:CONAN_PKG::ms-gsl>,CONAN_PKG::ms-gsl,Microsoft.GSL::GSL>
)
target_include_directories(units
target_include_directories(mp-units
INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
target_link_libraries(units
target_link_libraries(mp-units
INTERFACE
$<IF:$<TARGET_EXISTS:CONAN_PKG::range-v3>,CONAN_PKG::range-v3,range-v3::range-v3>
)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
target_compile_options(units
target_compile_options(mp-units
INTERFACE
-Wno-literal-suffix
-Wno-non-template-friend
)
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10.0)
target_compile_options(units
target_compile_options(mp-units
INTERFACE
-fconcepts
)
target_link_libraries(units
target_link_libraries(mp-units
INTERFACE
$<IF:$<TARGET_EXISTS:CONAN_PKG::range-v3>,CONAN_PKG::range-v3,range-v3::range-v3>
)
endif()
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
target_compile_options(units
target_compile_options(mp-units
INTERFACE
/utf-8 # Specifies both the source character set and the execution character set as UTF-8
/wd4455 # 'operator name': literal suffix identifiers that do not start with an underscore are reserved
)
endif()
add_library(mp::units ALIAS units)
add_library(mp-units::mp-units ALIAS mp-units)
# installation info
install_targets(units)
install_targets(mp-units)
install(DIRECTORY include/units
DESTINATION include
COMPONENT Devel
)
# generate configuration files and install the package
configure_and_install(../cmake/common/cmake/simple-config.cmake.in mp SameMajorVersion)
configure_and_install(../cmake/common/simple-config.cmake.in mp-units SameMajorVersion)

View File

@@ -0,0 +1,61 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <cstdint>
#include <cassert>
namespace units::detail {
constexpr std::intmax_t ipow10(std::intmax_t exp)
{
assert(exp >= 0);
if (exp == 0) return 1;
std::intmax_t result = 1;
while (exp > 0) {
result *= 10;
--exp;
}
return result;
}
template<typename Rep>
constexpr Rep fpow10(std::intmax_t exp)
{
if (exp == 0) return Rep(1.0);
Rep result = Rep(1.0);
if (exp < 0) {
while (exp < 0) {
result = result / Rep(10.0);
++exp;
}
} else {
while (exp > 0) {
result = result * Rep(10.0);
--exp;
}
}
return result;
}
} // namespace units::detail

View File

@@ -23,6 +23,7 @@
#pragma once
#include <units/bits/external/downcasting.h>
#include <units/concepts.h>
#include <units/ratio.h>
#include <units/symbol_text.h>

View File

@@ -25,6 +25,7 @@
#include <units/bits/common_quantity.h>
#include <units/bits/dimension_op.h>
#include <units/bits/pow.h>
#include <units/bits/to_string.h>
#include <units/quantity_cast.h>
@@ -342,9 +343,9 @@ template<typename D1, typename U1, typename Rep1, typename D2, typename U2, type
using common_rep = decltype(lhs.count() * rhs.count());
const ratio r = U1::ratio * U2::ratio;
if constexpr (treat_as_floating_point<common_rep>) {
return lhs.count() * rhs.count() * static_cast<common_rep>(r.num * fpow10<common_rep>(r.exp)) / static_cast<common_rep>(r.den);
return lhs.count() * rhs.count() * static_cast<common_rep>(r.num * detail::fpow10<common_rep>(r.exp)) / static_cast<common_rep>(r.den);
} else {
return lhs.count() * rhs.count() * static_cast<common_rep>(r.num * ipow10(r.exp)) / static_cast<common_rep>(r.den);
return lhs.count() * rhs.count() * static_cast<common_rep>(r.num * detail::ipow10(r.exp)) / static_cast<common_rep>(r.den);
}
}

View File

@@ -26,6 +26,9 @@
#include <units/customization_points.h>
#include <units/bits/dimension_op.h>
#include <units/bits/external/type_traits.h>
#include <units/bits/pow.h>
#include <units/quantity.h>
#include <units/quantity_point.h>
#include <cassert>
#ifdef _MSC_VER
@@ -35,38 +38,6 @@
namespace units {
constexpr std::intmax_t ipow10(std::intmax_t exp)
{
assert(exp >= 0);
if (exp == 0) return 1;
std::intmax_t result = 1;
while (exp > 0) {
result *= 10;
--exp;
}
return result;
}
template<typename Rep>
constexpr Rep fpow10(std::intmax_t exp)
{
if (exp == 0) return Rep(1.0);
Rep result = Rep(1.0);
if (exp < 0) {
while (exp < 0) {
result = result / Rep(10.0);
++exp;
}
} else {
while (exp > 0) {
result = result * Rep(10.0);
--exp;
}
}
return result;
}
// QuantityOf
template<typename T, typename Dim>
concept QuantityOf = Quantity<T> && Dimension<Dim> && equivalent_dim<typename T::dimension, Dim>;
@@ -92,13 +63,13 @@ struct quantity_cast_impl<To, CRatio, CRep, true, true, false> {
static constexpr To cast(const Q& q)
{
if constexpr (treat_as_floating_point<CRep>) {
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(fpow10<CRep>(CRatio.exp))));
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(detail::fpow10<CRep>(CRatio.exp))));
} else {
if constexpr (CRatio.exp > 0) {
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(ipow10(CRatio.exp))));
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(detail::ipow10(CRatio.exp))));
}
else {
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) / static_cast<CRep>(ipow10(-CRatio.exp))));
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) / static_cast<CRep>(detail::ipow10(-CRatio.exp))));
}
}
}
@@ -122,21 +93,21 @@ struct quantity_cast_impl<To, CRatio, CRep, false, false, false> {
{
if constexpr (treat_as_floating_point<CRep>) {
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) *
static_cast<CRep>(fpow10<CRep>(CRatio.exp)) *
static_cast<CRep>(detail::fpow10<CRep>(CRatio.exp)) *
(static_cast<CRep>(CRatio.num) /
static_cast<CRep>(CRatio.den))));
} else {
if constexpr (CRatio.exp > 0) {
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) *
static_cast<CRep>(CRatio.num) *
static_cast<CRep>(ipow10(CRatio.exp)) /
static_cast<CRep>(detail::ipow10(CRatio.exp)) /
static_cast<CRep>(CRatio.den)));
}
else {
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) *
static_cast<CRep>(CRatio.num) /
(static_cast<CRep>(CRatio.den) *
static_cast<CRep>(ipow10(-CRatio.exp)))));
static_cast<CRep>(detail::ipow10(-CRatio.exp)))));
}
}
}
@@ -157,13 +128,13 @@ struct quantity_cast_impl<To, CRatio, CRep, true, false, false> {
static constexpr To cast(const Q& q)
{
if constexpr (treat_as_floating_point<CRep>) {
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(fpow10<CRep>(CRatio.exp)) * (CRep{1} / static_cast<CRep>(CRatio.den))));
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(detail::fpow10<CRep>(CRatio.exp)) * (CRep{1} / static_cast<CRep>(CRatio.den))));
} else {
if constexpr (CRatio.exp > 0) {
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(ipow10(CRatio.exp)) / static_cast<CRep>(CRatio.den)));
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(detail::ipow10(CRatio.exp)) / static_cast<CRep>(CRatio.den)));
}
else {
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) / (static_cast<CRep>(ipow10(-CRatio.exp)) * static_cast<CRep>(CRatio.den))));
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) / (static_cast<CRep>(detail::ipow10(-CRatio.exp)) * static_cast<CRep>(CRatio.den))));
}
}
}
@@ -184,13 +155,13 @@ struct quantity_cast_impl<To, CRatio, CRep, false, true, false> {
static constexpr To cast(const Q& q)
{
if constexpr (treat_as_floating_point<CRep>) {
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CRatio.num) * static_cast<CRep>(fpow10<CRep>(CRatio.exp))));
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CRatio.num) * static_cast<CRep>(detail::fpow10<CRep>(CRatio.exp))));
} else {
if constexpr (CRatio.exp > 0) {
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CRatio.num) * static_cast<CRep>(ipow10(CRatio.exp))));
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CRatio.num) * static_cast<CRep>(detail::ipow10(CRatio.exp))));
}
else {
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CRatio.num) / static_cast<CRep>(ipow10(-CRatio.exp))));
return To(static_cast<TYPENAME To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CRatio.num) / static_cast<CRep>(detail::ipow10(-CRatio.exp))));
}
}
}
@@ -202,13 +173,13 @@ struct quantity_cast_impl<To, CRatio, CRep, true, true, false> {
static constexpr To cast(const Q& q)
{
if constexpr (treat_as_floating_point<CRep>) {
return To(static_cast<TYPENAME To::rep>(q.count() * fpow10<CRep>(CRatio.exp)));
return To(static_cast<TYPENAME To::rep>(q.count() * detail::fpow10<CRep>(CRatio.exp)));
} else {
if constexpr (CRatio.exp > 0) {
return To(static_cast<TYPENAME To::rep>(q.count() * ipow10(CRatio.exp)));
return To(static_cast<TYPENAME To::rep>(q.count() * detail::ipow10(CRatio.exp)));
}
else {
return To(static_cast<TYPENAME To::rep>(q.count() / ipow10(-CRatio.exp)));
return To(static_cast<TYPENAME To::rep>(q.count() / detail::ipow10(-CRatio.exp)));
}
}
}
@@ -229,13 +200,13 @@ struct quantity_cast_impl<To, CRatio, CRep, false, false, false> {
static constexpr To cast(const Q& q)
{
if constexpr (treat_as_floating_point<CRep>) {
return To(static_cast<TYPENAME To::rep>(q.count() * fpow10<CRep>(CRatio.exp) * (CRatio.num / CRatio.den)));
return To(static_cast<TYPENAME To::rep>(q.count() * detail::fpow10<CRep>(CRatio.exp) * (CRatio.num / CRatio.den)));
} else {
if constexpr (CRatio.exp > 0) {
return To(static_cast<TYPENAME To::rep>(q.count() * CRatio.num * ipow10(CRatio.exp) / CRatio.den));
return To(static_cast<TYPENAME To::rep>(q.count() * CRatio.num * detail::ipow10(CRatio.exp) / CRatio.den));
}
else {
return To(static_cast<TYPENAME To::rep>(q.count()) * CRatio.num / (CRatio.den * ipow10(-CRatio.exp)));
return To(static_cast<TYPENAME To::rep>(q.count()) * CRatio.num / (CRatio.den * detail::ipow10(-CRatio.exp)));
}
}
}
@@ -256,13 +227,13 @@ struct quantity_cast_impl<To, CRatio, CRep, true, false, false> {
static constexpr To cast(const Q& q)
{
if constexpr (treat_as_floating_point<CRep>) {
return To(static_cast<TYPENAME To::rep>(q.count() * fpow10<CRep>(CRatio.exp) / CRatio.den));
return To(static_cast<TYPENAME To::rep>(q.count() * detail::fpow10<CRep>(CRatio.exp) / CRatio.den));
} else {
if constexpr (CRatio.exp > 0) {
return To(static_cast<TYPENAME To::rep>(q.count() * ipow10(CRatio.exp) / CRatio.den));
return To(static_cast<TYPENAME To::rep>(q.count() * detail::ipow10(CRatio.exp) / CRatio.den));
}
else {
return To(static_cast<TYPENAME To::rep>(q.count() / (ipow10(-CRatio.exp) * CRatio.den)));
return To(static_cast<TYPENAME To::rep>(q.count() / (detail::ipow10(-CRatio.exp) * CRatio.den)));
}
}
}
@@ -283,13 +254,13 @@ struct quantity_cast_impl<To, CRatio, CRep, false, true, false> {
static constexpr To cast(const Q& q)
{
if constexpr (treat_as_floating_point<CRep>) {
return To(static_cast<TYPENAME To::rep>(q.count() * CRatio.num * fpow10<CRep>(CRatio.exp)));
return To(static_cast<TYPENAME To::rep>(q.count() * CRatio.num * detail::fpow10<CRep>(CRatio.exp)));
} else {
if constexpr (CRatio.exp > 0) {
return To(static_cast<TYPENAME To::rep>(q.count() * CRatio.num * ipow10(CRatio.exp)));
return To(static_cast<TYPENAME To::rep>(q.count() * CRatio.num * detail::ipow10(CRatio.exp)));
}
else {
return To(static_cast<TYPENAME To::rep>(q.count() * CRatio.num / ipow10(-CRatio.exp)));
return To(static_cast<TYPENAME To::rep>(q.count() * CRatio.num / detail::ipow10(-CRatio.exp)));
}
}
}

View File

@@ -29,6 +29,7 @@
#include <type_traits>
#include <tuple>
#include <algorithm>
#include <gsl/gsl_assert>
namespace units {
@@ -50,6 +51,7 @@ struct ratio {
explicit constexpr ratio(std::intmax_t n, std::intmax_t d = 1, std::intmax_t e = 0): num(n), den(d), exp(e)
{
Expects(den != 0);
detail::normalize(num, den, exp);
}

View File

@@ -20,6 +20,8 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
cmake_minimum_required(VERSION 3.12)
add_subdirectory(unit_test/runtime)
add_subdirectory(unit_test/static)
#add_subdirectory(metabench)

View File

@@ -20,6 +20,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
cmake_minimum_required(VERSION 3.12)
function(add_metabench_test target name erb_path range)
metabench_add_dataset(${target} "${erb_path}" "${range}" NAME "${name}")

View File

@@ -20,6 +20,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
cmake_minimum_required(VERSION 3.12)
add_metabench_test(metabench.data.list.type_list.concepts_all "all concepts" type_list_concepts_all.cpp.erb "[3, 6, 9, 12, 15]")
add_metabench_test(metabench.data.list.type_list.concepts_iface "concepts in interface" type_list_concepts_iface.cpp.erb "[3, 6, 9, 12, 15]")

View File

@@ -182,4 +182,4 @@ namespace units {
template<TypeList List, template<typename, typename> typename Pred>
using type_list_sort_t = type_list_sort<List, Pred>::type;
} // namespace units
} // namespace units

View File

@@ -20,6 +20,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
cmake_minimum_required(VERSION 3.12)
add_metabench_test(metabench.data.make_dimension.no_concepts "no concepts" no_concepts.cpp.erb "[1, 2, 3, 4, 6, 8, 10]")
add_metabench_test(metabench.data.make_dimension.concepts_iface "concepts iface" concepts_iface.cpp.erb "[1, 2, 3, 4, 6, 8, 10]")

View File

@@ -20,6 +20,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
cmake_minimum_required(VERSION 3.12)
add_metabench_test(metabench.data.ratio.create.std_ratio "std::ratio" create_std_ratio.cpp.erb "[1000, 2500, 5000, 7500, 10000]")
add_metabench_test(metabench.data.ratio.create.ratio_type_constexpr "ratio with constexpr" create_ratio_type_constexpr.cpp.erb "[1000, 2500, 5000, 7500, 10000]")

View File

@@ -20,6 +20,8 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
cmake_minimum_required(VERSION 3.12)
# check if conan installed a test framework
conan_check_testing(catch2)
@@ -33,7 +35,7 @@ add_executable(unit_tests_runtime
)
target_link_libraries(unit_tests_runtime
PRIVATE
mp::units
mp-units::mp-units
$<IF:$<TARGET_EXISTS:CONAN_PKG::catch2>,CONAN_PKG::catch2,Catch2::Catch2>
)

View File

@@ -606,4 +606,4 @@ TEST_CASE("piecewise_linear_distribution")
CHECK(units_dist.intervals() == intervals_qty_vec);
CHECK(units_dist.densities() == stl_dist.densities());
}
}
}

View File

@@ -938,7 +938,11 @@ TEST_CASE("precision specification", "[text][fmt]")
CHECK(fmt::format("{:%.0Q %q}", 1.2345q_m) == "1 m");
CHECK(fmt::format("{:%.1Q %q}", 1.2345q_m) == "1.2 m");
CHECK(fmt::format("{:%.2Q %q}", 1.2345q_m) == "1.23 m");
#ifdef COMP_MSVC
CHECK(fmt::format("{:%.3Q %q}", 1.2345q_m) == "1.234 m");
#else
CHECK(fmt::format("{:%.3Q %q}", 1.2345q_m) == "1.235 m");
#endif
CHECK(fmt::format("{:%.4Q %q}", 1.2345q_m) == "1.2345 m");
CHECK(fmt::format("{:%.5Q %q}", 1.2345q_m) == "1.23450 m");
CHECK(fmt::format("{:%.10Q %q}", 1.2345q_m) == "1.2345000000 m");
@@ -949,7 +953,11 @@ TEST_CASE("precision specification", "[text][fmt]")
CHECK(fmt::format("{:%.0Q}", 1.2345q_m) == "1");
CHECK(fmt::format("{:%.1Q}", 1.2345q_m) == "1.2");
CHECK(fmt::format("{:%.2Q}", 1.2345q_m) == "1.23");
#ifdef COMP_MSVC
CHECK(fmt::format("{:%.3Q}", 1.2345q_m) == "1.234");
#else
CHECK(fmt::format("{:%.3Q}", 1.2345q_m) == "1.235");
#endif
CHECK(fmt::format("{:%.4Q}", 1.2345q_m) == "1.2345");
CHECK(fmt::format("{:%.5Q}", 1.2345q_m) == "1.23450");
CHECK(fmt::format("{:%.10Q}", 1.2345q_m) == "1.2345000000");
@@ -980,10 +988,17 @@ TEST_CASE("type specification", "[text][fmt]")
CHECK(fmt::format("{:%xQ %q}", 42q_m) == "2a m");
CHECK(fmt::format("{:%XQ %q}", 42q_m) == "2A m");
#ifdef COMP_MSVC
CHECK(fmt::format("{:%aQ %q}", 1.2345678q_m) == "0x1.3c0ca2a5b1d5dp+0 m");
CHECK(fmt::format("{:%.3aQ %q}", 1.2345678q_m) == "0x1.3c1p+0 m");
CHECK(fmt::format("{:%AQ %q}", 1.2345678q_m) == "0X1.3C0CA2A5B1D5DP+0 m");
CHECK(fmt::format("{:%.3AQ %q}", 1.2345678q_m) == "0X1.3C1P+0 m");
#else
CHECK(fmt::format("{:%aQ %q}", 1.2345678q_m) == "0x9.e065152d8eae841p-3 m");
CHECK(fmt::format("{:%.3aQ %q}", 1.2345678q_m) == "0x9.e06p-3 m");
CHECK(fmt::format("{:%AQ %q}", 1.2345678q_m) == "0X9.E065152D8EAE841P-3 m");
CHECK(fmt::format("{:%.3AQ %q}", 1.2345678q_m) == "0X9.E06P-3 m");
#endif
CHECK(fmt::format("{:%eQ %q}", 1.2345678q_m) == "1.234568e+00 m");
CHECK(fmt::format("{:%.3eQ %q}", 1.2345678q_m) == "1.235e+00 m");
CHECK(fmt::format("{:%EQ %q}", 1.2345678q_m) == "1.234568E+00 m");
@@ -1007,10 +1022,17 @@ TEST_CASE("type specification", "[text][fmt]")
CHECK(fmt::format("{:%xQ}", 42q_m) == "2a");
CHECK(fmt::format("{:%XQ}", 42q_m) == "2A");
#ifdef COMP_MSVC
CHECK(fmt::format("{:%aQ}", 1.2345678q_m) == "0x1.3c0ca2a5b1d5dp+0");
CHECK(fmt::format("{:%.3aQ}", 1.2345678q_m) == "0x1.3c1p+0");
CHECK(fmt::format("{:%AQ}", 1.2345678q_m) == "0X1.3C0CA2A5B1D5DP+0");
CHECK(fmt::format("{:%.3AQ}", 1.2345678q_m) == "0X1.3C1P+0");
#else
CHECK(fmt::format("{:%aQ}", 1.2345678q_m) == "0x9.e065152d8eae841p-3");
CHECK(fmt::format("{:%.3aQ}", 1.2345678q_m) == "0x9.e06p-3");
CHECK(fmt::format("{:%AQ}", 1.2345678q_m) == "0X9.E065152D8EAE841P-3");
CHECK(fmt::format("{:%.3AQ}", 1.2345678q_m) == "0X9.E06P-3");
#endif
CHECK(fmt::format("{:%eQ}", 1.2345678q_m) == "1.234568e+00");
CHECK(fmt::format("{:%.3eQ}", 1.2345678q_m) == "1.235e+00");
CHECK(fmt::format("{:%EQ}", 1.2345678q_m) == "1.234568E+00");

View File

@@ -20,6 +20,8 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
cmake_minimum_required(VERSION 3.12)
add_library(unit_tests_static
cgs_test.cpp
custom_rep_min_req_test.cpp
@@ -43,5 +45,5 @@ add_library(unit_tests_static
)
target_link_libraries(unit_tests_static
PRIVATE
mp::units
mp-units::mp-units
)

View File

@@ -25,6 +25,7 @@
#include "units/physical/si/frequency.h"
#include "units/physical/si/speed.h"
#include <chrono>
#include <type_traits>
#include <utility>
using namespace units;
@@ -65,7 +66,7 @@ template<typename T>
struct expl_constructible : scalar_ops<expl_constructible<T>> {
T value_{};
expl_constructible() = default;
constexpr expl_constructible(T v) : value_(std::move(v)) {}
constexpr explicit expl_constructible(T v) : value_(std::move(v)) {}
// no conversion to fundamental arithmetic types
};
@@ -172,60 +173,60 @@ using namespace units::physical::si;
// Quantity from Scalar
// int <- int
static_assert(length<metre, int>(expl_impl<int>(1)).count() == 1);
// static_assert(length<metre, int>(impl_expl<int>(1)).count() == 1); // should not compile (not convertible)
static_assert(!std::is_constructible_v<length<metre, int>, impl_expl<int>>);
static_assert(length<metre, int>(int(impl_expl<int>(1))).count() == 1);
// static_assert(length<metre, expl_impl<int>>(1).count() == expl_impl<int>{1}); // should not compile (not convertible)
static_assert(!std::is_constructible_v<length<metre, expl_impl<int>>, int>);
static_assert(length<metre, expl_impl<int>>(expl_impl<int>(1)).count() == expl_impl<int>{1});
static_assert(length<metre, impl_expl<int>>(1).count() == impl_expl<int>{1});
// double <- double
static_assert(length<metre, double>(expl_impl<double>(1.0)).count() == 1.0);
// static_assert(length<metre, double>(impl_expl<double>(1.0)).count() == 1.0); // should not compile (not convertible)
static_assert(!std::is_constructible_v<length<metre, double>, impl_expl<double>>);
static_assert(length<metre, double>(double(impl_expl<double>(1.0))).count() == 1.0);
// static_assert(length<metre, expl_impl<double>>(1.0).count() == expl_impl<double>{1.0}); // should not compile (not convertible)
static_assert(!std::is_constructible_v<length<metre, expl_impl<double>>, double>);
static_assert(length<metre, expl_impl<double>>(expl_impl<double>(1.0)).count() == expl_impl<double>{1.0});
static_assert(length<metre, impl_expl<double>>(1.0).count() == impl_expl<double>{1.0});
// double <- int
static_assert(length<metre, double>(expl_impl<int>(1)).count() == 1.0);
// static_assert(length<metre, double>(impl_expl<int>(1)).count() == 1.0); // should not compile (not convertible)
static_assert(!std::is_constructible_v<length<metre, double>, impl_expl<int>>);
static_assert(length<metre, double>(int(impl_expl<int>(1))).count() == 1.0);
// static_assert(length<metre, expl_impl<double>>(1).count() == expl_impl<double>{1}); // should not compile (not convertible)
static_assert(!std::is_constructible_v<length<metre, expl_impl<double>>, int>);
static_assert(length<metre, expl_impl<double>>(expl_impl<double>(1)).count() == expl_impl<double>{1});
static_assert(length<metre, impl_expl<double>>(1).count() == impl_expl<double>{1.0});
// int <- double
// static_assert(length<metre, int>(expl_impl<double>(1.0)).count() == 1); // should not compile (truncating conversion)
// static_assert(length<metre, impl_expl<int>>(1.0).count() == impl_expl<int>{1}); // should not compile (truncating conversion)
static_assert(!std::is_constructible_v<length<metre, int>, expl_impl<double>>);
static_assert(!std::is_constructible_v<length<metre, impl_expl<int>>, double>);
// Quantity from other Quantity with different Rep
// int <- int
static_assert(length<metre, int>(length<metre, expl_impl<int>>(expl_impl<int>(1))).count() == 1);
// static_assert(length<metre, int>(length<metre, impl_expl<int>>(1)).count() == 1); // should not compile (not convertible)
static_assert(!std::is_constructible_v<length<metre, int>, length<metre, impl_expl<int>>>);
static_assert(length<metre, int>(quantity_cast<int>(length<metre, impl_expl<int>>(1))).count() == 1);
// static_assert(length<metre, expl_impl<int>>(length<metre, int>(1)).count() == expl_impl<int>{1}); // should not compile (not convertible)
static_assert(!std::is_constructible_v<length<metre, expl_impl<int>>, length<metre, int>>);
static_assert(length<metre, expl_impl<int>>(quantity_cast<expl_impl<int>>(length<metre, int>(1))).count() == expl_impl<int>{1});
static_assert(length<metre, impl_expl<int>>(length<metre, int>(1)).count() == impl_expl<int>{1});
// double <- double
static_assert(length<metre, double>(length<metre, expl_impl<double>>(expl_impl<double>(1.0))).count() == 1.0);
// static_assert(length<metre, double>(length<metre, impl_expl<double>>(1.0)).count() == 1.0); // should not compile (not convertible)
static_assert(!std::is_constructible_v<length<metre, double>, length<metre, impl_expl<double>>>);
static_assert(length<metre, double>(quantity_cast<double>(length<metre, impl_expl<double>>(1.0))).count() == 1.0);
// static_assert(length<metre, expl_impl<double>>(length<metre>(1.0).count() == expl_impl<double>{1.0}); // should not compile (not convertible)
static_assert(!std::is_constructible_v<length<metre, expl_impl<double>>, length<metre, double>>);
static_assert(length<metre, expl_impl<double>>(quantity_cast<expl_impl<double>>(length<metre>(1.0))).count() == expl_impl<double>{1.0});
static_assert(length<metre, impl_expl<double>>(length<metre>(1.0)).count() == impl_expl<double>{1.0});
// double <- int
static_assert(length<metre, double>(length<metre, expl_impl<int>>(expl_impl<int>(1))).count() == 1.0);
// static_assert(length<metre, double>(length<metre, impl_expl<int>>(1)).count() == 1.0); // should not compile (not convertible)
static_assert(!std::is_constructible_v<length<metre, double>, length<metre, impl_expl<int>>>);
static_assert(length<metre, double>(quantity_cast<int>(length<metre, impl_expl<int>>(1))).count() == 1.0);
// static_assert(length<metre, expl_impl<double>>(length<metre, int>(1)).count() == expl_impl<double>{1}); // should not compile (not convertible)
static_assert(!std::is_constructible_v<length<metre, expl_impl<double>>, length<metre, int>>);
static_assert(length<metre, expl_impl<double>>(quantity_cast<expl_impl<double>>(length<metre, int>(1))).count() == expl_impl<double>{1});
static_assert(length<metre, impl_expl<double>>(length<metre, int>(1)).count() == impl_expl<double>{1.0});
// int <- double
// static_assert(length<metre, int>(length<metre, expl_impl<double>>(1.0)).count() == 1); // should not compile (truncating conversion)
// static_assert(length<metre, impl_expl<int>>(length<metre, double>(1.0)).count() == impl_expl<int>{1}); // should not compile (truncating conversion)
static_assert(!std::is_constructible_v<length<metre, int>, length<metre, expl_impl<double>>>);
static_assert(!std::is_constructible_v<length<metre, impl_expl<int>>, length<metre, double>>);
// unit conversions
@@ -236,43 +237,43 @@ static_assert(length<metre, impl_expl<int>>(length<kilometre, impl_expl<int>>(1)
static_assert(length<metre, expl_impl<int>>(length<kilometre, expl_impl<int>>(expl_impl<int>(1))).count() == expl_impl<int>(1000));
static_assert(length<metre, expl_expl<int>>(length<kilometre, expl_expl<int>>(expl_expl<int>(1))).count() == expl_expl<int>(1000));
// static_assert(length<kilometre, impl<int>>(length<metre, impl<int>>(2000)).count() == impl<int>(2)); // should not compile (truncating conversion)
static_assert(!std::is_constructible_v<length<kilometre, impl<int>>, length<metre, impl<int>>>);
static_assert(length<kilometre, impl<int>>(quantity_cast<kilometre>(length<metre, impl<int>>(2000))).count() == impl<int>(2));
// static_assert(length<kilometre, expl<int>>(length<metre, expl<int>>(expl<int>(2000))).count() == expl<int>(2)); // should not compile (truncating conversion)
static_assert(!std::is_constructible_v<length<kilometre, expl<int>>, length<metre, expl<int>>>);
static_assert(length<kilometre, expl<int>>(quantity_cast<kilometre>(length<metre, expl<int>>(expl<int>(2000)))).count() == expl<int>(2));
// static_assert(length<kilometre, impl_impl<int>>(length<metre, impl_impl<int>>(2000)).count() == impl_impl<int>(2)); // should not compile (truncating conversion)
static_assert(!std::is_constructible_v<length<kilometre, impl_impl<int>>, length<metre, impl_impl<int>>>);
static_assert(length<kilometre, impl_impl<int>>(quantity_cast<kilometre>(length<metre, impl_impl<int>>(2000))).count() == impl_impl<int>(2));
// static_assert(length<kilometre, impl_expl<int>>(length<metre, impl_expl<int>>(2000)).count() == impl_expl<int>(2)); // should not compile (truncating conversion)
static_assert(!std::is_constructible_v<length<kilometre, impl_expl<int>>, length<metre, impl_expl<int>>>);
static_assert(length<kilometre, impl_expl<int>>(quantity_cast<kilometre>(length<metre, impl_expl<int>>(2000))).count() == impl_expl<int>(2));
// static_assert(length<kilometre, expl_impl<int>>(length<metre, expl_impl<int>>(expl_impl<int>(2000))).count() == expl_impl<int>(2)); // should not compile (truncating conversion)
static_assert(!std::is_constructible_v<length<kilometre, expl_impl<int>>, length<metre, expl_impl<int>>>);
static_assert(length<kilometre, expl_impl<int>>(quantity_cast<kilometre>(length<metre, expl_impl<int>>(expl_impl<int>(2000)))).count() == expl_impl<int>(2));
// static_assert(length<kilometre, expl_expl<int>>(length<metre, expl_expl<int>>(expl_expl<int>(2000))).count() == expl_expl<int>(2)); // should not compile (truncating conversion)
static_assert(!std::is_constructible_v<length<kilometre, expl_expl<int>>, length<metre, expl_expl<int>>>);
static_assert(length<kilometre, expl_expl<int>>(quantity_cast<kilometre>(length<metre, expl_expl<int>>(expl_expl<int>(2000)))).count() == expl_expl<int>(2));
// static_assert(speed<metre_per_second, impl<int>>(speed<kilometre_per_hour, impl<int>>(72)).count() == impl<int>(20)); // should not compile (truncating conversion)
static_assert(!std::is_constructible_v<speed<metre_per_second, impl<int>>, speed<kilometre_per_hour, impl<int>>>);
static_assert(speed<metre_per_second, impl<int>>(quantity_cast<metre_per_second>(speed<kilometre_per_hour, impl<int>>(72))).count() == impl<int>(20));
// static_assert(speed<metre_per_second, expl<int>>(speed<kilometre_per_hour, expl<int>>(expl(72))).count() == expl<int>(20)); // should not compile (truncating conversion)
static_assert(!std::is_constructible_v<speed<metre_per_second, expl<int>>, speed<kilometre_per_hour, expl<int>>>);
static_assert(speed<metre_per_second, expl<int>>(quantity_cast<metre_per_second>(speed<kilometre_per_hour, expl<int>>(expl<int>(72)))).count() == expl<int>(20));
// static_assert(speed<metre_per_second, impl_impl<int>>(speed<kilometre_per_hour, impl_impl<int>>(72)).count() == impl_impl<int>(20)); // should not compile (truncating conversion)
static_assert(!std::is_constructible_v<speed<metre_per_second, impl_impl<int>>, speed<kilometre_per_hour, impl_impl<int>>>);
static_assert(speed<metre_per_second, impl_impl<int>>(quantity_cast<metre_per_second>(speed<kilometre_per_hour, impl_impl<int>>(72))).count() == impl_impl<int>(20));
// static_assert(speed<metre_per_second, impl_expl<int>>(speed<kilometre_per_hour, impl_expl<int>>(72)).count() == impl_expl<int>(20)); // should not compile (truncating conversion)
static_assert(!std::is_constructible_v<speed<metre_per_second, impl_expl<int>>, speed<kilometre_per_hour, impl_expl<int>>>);
static_assert(speed<metre_per_second, impl_expl<int>>(quantity_cast<metre_per_second>(speed<kilometre_per_hour, impl_expl<int>>(72))).count() == impl_expl<int>(20));
// static_assert(speed<metre_per_second, expl_impl<int>>(speed<kilometre_per_hour, expl_impl<int>>(expl_impl(72))).count() == expl_impl<int>(20)); // should not compile (truncating conversion)
static_assert(!std::is_constructible_v<speed<metre_per_second, expl_impl<int>>, speed<kilometre_per_hour, expl_impl<int>>>);
static_assert(speed<metre_per_second, expl_impl<int>>(quantity_cast<metre_per_second>(speed<kilometre_per_hour, expl_impl<int>>(expl_impl<int>(72)))).count() == expl_impl<int>(20));
// static_assert(speed<metre_per_second, expl_expl<int>>(speed<kilometre_per_hour, expl_expl<int>>(expl_expl(72))).count() == expl_expl<int>(20)); // should not compile (truncating conversion)
static_assert(!std::is_constructible_v<speed<metre_per_second, expl_expl<int>>, speed<kilometre_per_hour, expl_expl<int>>>);
static_assert(speed<metre_per_second, expl_expl<int>>(quantity_cast<metre_per_second>(speed<kilometre_per_hour, expl_expl<int>>(expl_expl<int>(72)))).count() == expl_expl<int>(20));
// static_assert(speed<kilometre_per_hour, impl<int>>(speed<metre_per_second, impl<int>>(20)).count() == impl<int>(72)); // should not compile (truncating conversion)
static_assert(!std::is_constructible_v<speed<kilometre_per_hour, impl<int>>, speed<metre_per_second, impl<int>>>);
static_assert(speed<kilometre_per_hour, impl<int>>(quantity_cast<kilometre_per_hour>(speed<metre_per_second, impl<int>>(20))).count() == impl<int>(72));
// static_assert(speed<kilometre_per_hour, expl<int>>(speed<metre_per_second, expl<int>>(expl<int>(20))).count() == expl<int>(72)); // should not compile (truncating conversion)
static_assert(!std::is_constructible_v<speed<kilometre_per_hour, expl<int>>, speed<metre_per_second, expl<int>>>);
static_assert(speed<kilometre_per_hour, expl<int>>(quantity_cast<kilometre_per_hour>(speed<metre_per_second, expl<int>>(expl<int>(20)))).count() == expl<int>(72));
// static_assert(speed<kilometre_per_hour, impl_impl<int>>(speed<metre_per_second, impl_impl<int>>(20)).count() == impl_impl<int>(72)); // should not compile (truncating conversion)
static_assert(!std::is_constructible_v<speed<kilometre_per_hour, impl_impl<int>>, speed<metre_per_second, impl_impl<int>>>);
static_assert(speed<kilometre_per_hour, impl_impl<int>>(quantity_cast<kilometre_per_hour>(speed<metre_per_second, impl_impl<int>>(20))).count() == impl_impl<int>(72));
// static_assert(speed<kilometre_per_hour, impl_expl<int>>(speed<metre_per_second, impl_expl<int>>(20)).count() == impl_expl<int>(72)); // should not compile (truncating conversion)
static_assert(!std::is_constructible_v<speed<kilometre_per_hour, impl_expl<int>>, speed<metre_per_second, impl_expl<int>>>);
static_assert(speed<kilometre_per_hour, impl_expl<int>>(quantity_cast<kilometre_per_hour>(speed<metre_per_second, impl_expl<int>>(20))).count() == impl_expl<int>(72));
// static_assert(speed<kilometre_per_hour, expl_impl<int>>(speed<metre_per_second, expl_impl<int>>(expl_impl<int>(20))).count() == expl_impl<int>(72)); // should not compile (truncating conversion)
static_assert(!std::is_constructible_v<speed<kilometre_per_hour, expl_impl<int>>, speed<metre_per_second, expl_impl<int>>>);
static_assert(speed<kilometre_per_hour, expl_impl<int>>(quantity_cast<kilometre_per_hour>(speed<metre_per_second, expl_impl<int>>(expl_impl<int>(20)))).count() == expl_impl<int>(72));
// static_assert(speed<kilometre_per_hour, expl_expl<int>>(speed<metre_per_second, expl_expl<int>>(expl_expl<int>(20))).count() == expl_expl<int>(72)); // should not compile (truncating conversion)
static_assert(!std::is_constructible_v<speed<kilometre_per_hour, expl_expl<int>>, speed<metre_per_second, expl_expl<int>>>);
static_assert(speed<kilometre_per_hour, expl_expl<int>>(quantity_cast<kilometre_per_hour>(speed<metre_per_second, expl_expl<int>>(expl_expl<int>(20)))).count() == expl_expl<int>(72));
} // namespace

View File

@@ -47,7 +47,7 @@ concept invalid_types = requires
!requires { typename quantity<metre, DimLength, double>; }; // reordered arguments
};
static_assert(invalid_types<physical::si::dim_length>);
static_assert(invalid_types<dim_length>);
// member types
@@ -226,14 +226,19 @@ static_assert(quantity_point_cast<int>(quantity_point(1.23q_m)).relative().count
// time
#if COMP_MSVC || COMP_GCC >= 10
static_assert(!std::equality_comparable_with<quantity_point<dim_time, second, int>,
quantity_point<dim_length, metre, int>>); // different dimensions
#endif
static_assert(quantity_point{1q_h} == quantity_point{3600q_s});
template<typename Metre>
concept no_crossdimensional_equality = !requires
{
quantity_point(1q_s) == quantity_point(length<Metre, int>(1));
};
static_assert(no_crossdimensional_equality<metre>);
// length
static_assert(quantity_point(1q_km) != quantity_point(1q_m));
static_assert(quantity_point(1q_km) == quantity_point(1000q_m));
static_assert(quantity_point(1q_km) + 1q_m == quantity_point(1001q_m));
static_assert(1q_km + quantity_point(1q_m) == quantity_point(1001q_m));

View File

@@ -36,10 +36,15 @@ using namespace units::physical::si;
// class invariants
// constexpr quantity<si::dim_length, second, int> error(0); // should not compile (unit of a different dimension)
// constexpr quantity<si::dim_length, metre, quantity<si::dim_length, metre, int>> error(0); // should not compile (quantity used as Rep)
// constexpr quantity<metre, si::dim_length, double> error(0); // should not compile (reordered arguments)
// constexpr quantity<si::dim_length, scaled_unit<ratio(-1, 1), metre>, int> error(0); // should not compile (negative unit ratio)
template<typename DimLength>
concept invalid_types = requires
{
!requires { typename quantity<DimLength, second, int>; }; // unit of a different dimension
!requires { typename quantity<DimLength, metre, quantity<DimLength, metre, int>>; }; // quantity used as Rep
!requires { typename quantity<metre, DimLength, double>; }; // reordered arguments
};
static_assert(invalid_types<dim_length>);
// member types
@@ -56,18 +61,21 @@ static_assert(km.count() == 1000);
static_assert(length<metre, int>(km).count() == km.count());
static_assert(length<metre, int>(1).count() == 1);
// static_assert(length<metre, int>(1.0).count() == 1); // should not compile (truncating conversion)
static_assert(!std::is_constructible_v<length<metre, int>, double>); // truncating conversion
static_assert(length<metre, double>(1.0).count() == 1.0);
static_assert(length<metre, double>(1).count() == 1.0);
static_assert(length<metre, double>(3.14).count() == 3.14);
static_assert(length<metre, int>(km).count() == 1000);
// static_assert(length<metre, int>(length<metre, double>(3.14)).count() == 3); // should not compile (truncating conversion)
static_assert(!std::is_constructible_v<length<metre, int>,
length<metre, double>>); // truncating conversion
static_assert(length<metre, double>(1000.0q_m).count() == 1000.0);
static_assert(length<metre, double>(km).count() == 1000.0);
static_assert(length<metre, int>(1q_km).count() == 1000);
// static_assert(length<metre, int>(1q_s).count() == 1); // should not compile (different dimensions)
//static_assert(length<kilometre, int>(1010q_m).count() == 1); // should not compile (truncating conversion)
static_assert(!std::is_constructible_v<length<metre, int>,
physical::si::time<second, int>>); // different dimensions
static_assert(!std::is_constructible_v<length<kilometre, int>,
length<metre, int>>); // truncating conversion
// assignment operator
@@ -89,24 +97,22 @@ static_assert((-km).count() == -1000);
static_assert((+(-km)).count() == -1000);
static_assert((-(-km)).count() == 1000);
// binary member operators
static_assert([](auto v) {
auto vv = v++;
return std::make_pair(v, vv);
}(km) == std::make_pair(length<metre, int>(1001), length<metre, int>(1000)));
return std::pair(v, vv);
}(km) == std::pair(length<metre, int>(1001), length<metre, int>(1000)));
static_assert([](auto v) {
auto vv = ++v;
return std::make_pair(v, vv);
}(km) == std::make_pair(length<metre, int>(1001), length<metre, int>(1001)));
return std::pair(v, vv);
}(km) == std::pair(length<metre, int>(1001), length<metre, int>(1001)));
static_assert([](auto v) {
auto vv = v--;
return std::make_pair(v, vv);
}(km) == std::make_pair(length<metre, int>(999), length<metre, int>(1000)));
return std::pair(v, vv);
}(km) == std::pair(length<metre, int>(999), length<metre, int>(1000)));
static_assert([](auto v) {
auto vv = --v;
return std::make_pair(v, vv);
}(km) == std::make_pair(length<metre, int>(999), length<metre, int>(999)));
return std::pair(v, vv);
}(km) == std::pair(length<metre, int>(999), length<metre, int>(999)));
// compound assignment
@@ -116,22 +122,29 @@ static_assert((1q_m *= 2).count() == 2);
static_assert((2q_m /= 2).count() == 1);
static_assert((7q_m %= 2).count() == 1);
static_assert((7q_m %= 2q_m).count() == 1);
// static_assert((7.m %= 2.).count() == 1); // should not compile (operation not allowed for floating-point types)
// static_assert((7.m %= 2).count() == 1); // should not compile (operation not allowed for floating-point types)
// static_assert((7q_m %= 2.).count() == 1); // should not compile (operation not allowed for floating-point types)
static_assert((7q_m %= 2q_m).count() == 1);
// static_assert((7.m %= 2.m).count() == 1); // should not compile (operation not allowed for floating-point types)
// static_assert((7.m %= 2q_m).count() == 1); // should not compile (operation not allowed for floating-point types)
// static_assert((7q_m %= 2.m).count() == 1); // should not compile (operation not allowed for floating-point types)
// static_assert(2q_m += 3.5q_m); // should not compile
static_assert((2.5q_m += 3q_m).count() == 5.5);
static_assert((2.5q_m += 3.5q_m).count() == 6);
// static_assert(2q_m *= 3.5); // should not compile
static_assert((2.5q_m *= 3).count() == 7.5);
static_assert((2.5q_m *= 3.5).count() == 8.75);
// operations not allowed for the respective quantities
template<typename Metre>
concept invalid_compound_assignments = requires()
{
!requires(length<Metre, double> l) { l %= 2.; };
!requires(length<Metre, double> l) { l %= 2; };
!requires(length<Metre, int> l) { l %= 2.; };
!requires(length<Metre, double> l) { l %= 2.q_m; };
!requires(length<Metre, double> l) { l %= 2q_m; };
!requires(length<Metre, int> l) { l %= 2.q_m; };
!requires(length<Metre, int> l) { l += 3.5q_m; };
!requires(length<Metre, int> l) { l *= 3.5q_m; };
};
static_assert(invalid_compound_assignments<metre>);
// non-member arithmetic operators
static_assert(is_same_v<decltype(length<metre, int>() + length<metre, double>()), length<metre, double>>);
@@ -253,9 +266,13 @@ static_assert(quantity_cast<int>(1.23q_m).count() == 1);
// time
// static_assert(1q_s == 1q_m); // should not compile (different dimensions)
static_assert(1q_h == 3600q_s);
template<typename Metre>
concept no_crossdimensional_equality = !requires { 1q_s == length<Metre, int>(1); };
static_assert(no_crossdimensional_equality<metre>);
// length
static_assert(1q_km == 1000q_m);

View File

@@ -29,7 +29,6 @@ using namespace units;
static_assert(ratio(2, 4) == ratio(1, 2));
// basic exponents tests
// note use of ::type is required because template params are changed while stamping out template
static_assert(ratio(2, 40, 1) == ratio(1, 20, 1));
static_assert(ratio(20, 4, -1) == ratio(10, 2, -1));
static_assert(ratio(200, 5) == ratio(20'000, 50, -1));

View File

@@ -40,7 +40,10 @@ struct hour : named_scaled_unit<hour, "h", no_prefix, ratio(36, 1, 2), second> {
struct dim_time : base_dimension<"time", second> {};
struct kelvin : named_unit<kelvin, "K", no_prefix> {};
// struct kilokelvin : prefixed_unit<kilokelvin, si::kilo, kelvin> {}; // should not compile (prefix not allowed for this reference unit)
#if COMP_GCC >= 10
static_assert([]<Prefix P>(P) { return !requires { typename prefixed_unit<struct kilokelvin, P, kelvin>; }; }(si::kilo{})); // no prefix allowed
#endif
struct metre_per_second : unit<metre_per_second> {};
struct dim_speed : derived_dimension<dim_speed, metre_per_second, units::exp<dim_length, 1>, units::exp<dim_time, -1>> {};
@@ -52,6 +55,10 @@ static_assert(is_same_v<downcast<scaled_unit<ratio(yard::ratio.num, yard::ratio.
static_assert(is_same_v<downcast<scaled_unit<yard::ratio * ratio(1, 3), metre>>, foot>);
static_assert(is_same_v<downcast<scaled_unit<kilometre::ratio / hour::ratio, metre_per_second>>, kilometre_per_hour>);
#if COMP_GCC >= 10
static_assert([]<ratio R>() { return !requires { typename scaled_unit<R, metre>; }; }.template operator()<ratio(-1, 1)>()); // negative unit ratio
#endif
static_assert(centimetre::symbol == "cm");
static_assert(kilometre::symbol == "km");
static_assert(kilometre_per_hour::symbol == "km/h");

View File

@@ -20,16 +20,14 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
cmake_minimum_required(VERSION 2.8.12)
cmake_minimum_required(VERSION 3.12)
project(test_package)
set(CMAKE_VERBOSE_MAKEFILE TRUE)
# set path to custom cmake modules
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../cmake")
# compilation options and flags used in a project development process
include(common/cmake/scripts)
include(common/scripts)
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup(TARGETS)
@@ -41,4 +39,4 @@ target_link_libraries(${PROJECT_NAME}_conan PRIVATE CONAN_PKG::mp-units)
# test cmake-generated target
find_package(mp-units CONFIG REQUIRED)
add_executable(${PROJECT_NAME}_cmake test_package.cpp)
target_link_libraries(${PROJECT_NAME}_cmake PRIVATE mp::units)
target_link_libraries(${PROJECT_NAME}_cmake PRIVATE mp-units::mp-units)