From 5f31ccfc50fd6b950064958c1afa4639cdac64c3 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Sat, 5 Sep 2020 22:01:47 +0200 Subject: [PATCH 01/22] CMake common scripts updated --- cmake/common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/common b/cmake/common index eb5fbd40..b951a327 160000 --- a/cmake/common +++ b/cmake/common @@ -1 +1 @@ -Subproject commit eb5fbd40d1cb765c5a8bf50866db86082c72ef73 +Subproject commit b951a32791923f22f9992fc297c111e472c93a4f From 9cd8bd20a5995a114351299e251ddce67bbdb7f6 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Sat, 5 Sep 2020 22:54:57 +0200 Subject: [PATCH 02/22] fmt tests fixed for MSVC --- test/unit_test/runtime/fmt_test.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/unit_test/runtime/fmt_test.cpp b/test/unit_test/runtime/fmt_test.cpp index 4a185fad..131105e6 100644 --- a/test/unit_test/runtime/fmt_test.cpp +++ b/test/unit_test/runtime/fmt_test.cpp @@ -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"); From 2078de7151c12a251fefa963b018791fd1b1cd61 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Sat, 5 Sep 2020 22:57:40 +0200 Subject: [PATCH 03/22] CHANGELOG updated --- docs/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index da7b9dce..9eb369d1 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -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)) From 32779e01f0eb92470b41a7d569dd79608646c551 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Sun, 6 Sep 2020 00:00:06 +0200 Subject: [PATCH 04/22] Build system refactored to be comatible with ConanCenter --- CMakeLists.txt | 2 +- conanfile.py | 65 +++++++++++-------- docs/CMakeLists.txt | 2 + example/CMakeLists.txt | 4 +- example/alternative_namespaces/CMakeLists.txt | 4 +- src/CMakeLists.txt | 26 ++++---- test/CMakeLists.txt | 2 + test/metabench/CMakeLists.txt | 1 + test/metabench/list/CMakeLists.txt | 1 + test/metabench/list/type_list_concepts_all.h | 2 +- test/metabench/make_dimension/CMakeLists.txt | 1 + test/metabench/ratio/CMakeLists.txt | 1 + test/unit_test/runtime/CMakeLists.txt | 4 +- test/unit_test/runtime/distribution_test.cpp | 2 +- test/unit_test/static/CMakeLists.txt | 4 +- test_package/CMakeLists.txt | 6 +- 16 files changed, 77 insertions(+), 50 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ce7bf7c0..08831032 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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() diff --git a/conanfile.py b/conanfile.py index 21241a87..a757b5dd 100644 --- a/conanfile.py +++ b/conanfile.py @@ -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" + ] diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index 57fabf75..c595a723 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -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() diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 8a6fc23b..3a2d15ee 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -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) diff --git a/example/alternative_namespaces/CMakeLists.txt b/example/alternative_namespaces/CMakeLists.txt index 6f3bc3d7..6341730c 100644 --- a/example/alternative_namespaces/CMakeLists.txt +++ b/example/alternative_namespaces/CMakeLists.txt @@ -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) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 915bf5b9..23332d47 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -37,8 +37,8 @@ include(common/cmake/scripts) 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 $,CONAN_PKG::fmt,fmt::fmt> $,CONAN_PKG::ms-gsl,Microsoft.GSL::GSL> ) -target_include_directories(units +target_include_directories(mp-units INTERFACE $ $ ) if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - target_link_libraries(units + target_link_libraries(mp-units INTERFACE $,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 $,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/cmake/simple-config.cmake.in mp-units SameMajorVersion) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 67a1d088..32c5ea73 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -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) diff --git a/test/metabench/CMakeLists.txt b/test/metabench/CMakeLists.txt index a7894a18..8264d434 100644 --- a/test/metabench/CMakeLists.txt +++ b/test/metabench/CMakeLists.txt @@ -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}") diff --git a/test/metabench/list/CMakeLists.txt b/test/metabench/list/CMakeLists.txt index fb1b5b97..c8776f04 100644 --- a/test/metabench/list/CMakeLists.txt +++ b/test/metabench/list/CMakeLists.txt @@ -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]") diff --git a/test/metabench/list/type_list_concepts_all.h b/test/metabench/list/type_list_concepts_all.h index 0344bdc9..62255427 100644 --- a/test/metabench/list/type_list_concepts_all.h +++ b/test/metabench/list/type_list_concepts_all.h @@ -182,4 +182,4 @@ namespace units { template typename Pred> using type_list_sort_t = type_list_sort::type; -} // namespace units \ No newline at end of file +} // namespace units diff --git a/test/metabench/make_dimension/CMakeLists.txt b/test/metabench/make_dimension/CMakeLists.txt index 63fdff45..c3d7c39b 100644 --- a/test/metabench/make_dimension/CMakeLists.txt +++ b/test/metabench/make_dimension/CMakeLists.txt @@ -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]") diff --git a/test/metabench/ratio/CMakeLists.txt b/test/metabench/ratio/CMakeLists.txt index fe5e2ca2..a3cc5fea 100644 --- a/test/metabench/ratio/CMakeLists.txt +++ b/test/metabench/ratio/CMakeLists.txt @@ -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]") diff --git a/test/unit_test/runtime/CMakeLists.txt b/test/unit_test/runtime/CMakeLists.txt index 0a727dbb..dc1ea76c 100644 --- a/test/unit_test/runtime/CMakeLists.txt +++ b/test/unit_test/runtime/CMakeLists.txt @@ -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 $,CONAN_PKG::catch2,Catch2::Catch2> ) diff --git a/test/unit_test/runtime/distribution_test.cpp b/test/unit_test/runtime/distribution_test.cpp index 9422fd90..101d569c 100644 --- a/test/unit_test/runtime/distribution_test.cpp +++ b/test/unit_test/runtime/distribution_test.cpp @@ -606,4 +606,4 @@ TEST_CASE("piecewise_linear_distribution") CHECK(units_dist.intervals() == intervals_qty_vec); CHECK(units_dist.densities() == stl_dist.densities()); } -} \ No newline at end of file +} diff --git a/test/unit_test/static/CMakeLists.txt b/test/unit_test/static/CMakeLists.txt index a5fe55e3..afe82e06 100644 --- a/test/unit_test/static/CMakeLists.txt +++ b/test/unit_test/static/CMakeLists.txt @@ -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 ) diff --git a/test_package/CMakeLists.txt b/test_package/CMakeLists.txt index 559377d3..b59831c0 100644 --- a/test_package/CMakeLists.txt +++ b/test_package/CMakeLists.txt @@ -20,11 +20,9 @@ # 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") @@ -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) From 40fb1e1e8bbc9d3a3f6fa268451b8a000d0a6b89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johel=20Ernesto=20Guerrero=20Pe=C3=B1a?= Date: Mon, 31 Aug 2020 22:49:43 -0400 Subject: [PATCH 05/22] fix: iwyu --- src/include/units/prefix.h | 1 + src/include/units/quantity_cast.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/include/units/prefix.h b/src/include/units/prefix.h index fbf45665..129be0b3 100644 --- a/src/include/units/prefix.h +++ b/src/include/units/prefix.h @@ -23,6 +23,7 @@ #pragma once #include +#include #include #include diff --git a/src/include/units/quantity_cast.h b/src/include/units/quantity_cast.h index 14bfbd5b..42f3118b 100644 --- a/src/include/units/quantity_cast.h +++ b/src/include/units/quantity_cast.h @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #ifdef _MSC_VER From 2f5be094b223f96d817bbda6fbc2d9e255342376 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johel=20Ernesto=20Guerrero=20Pe=C3=B1a?= Date: Mon, 31 Aug 2020 23:19:38 -0400 Subject: [PATCH 06/22] refactor: pow10 functions to pow.h --- src/include/units/pow.h | 61 +++++++++++++++++++++++++++++++ src/include/units/quantity.h | 1 + src/include/units/quantity_cast.h | 33 +---------------- 3 files changed, 63 insertions(+), 32 deletions(-) create mode 100644 src/include/units/pow.h diff --git a/src/include/units/pow.h b/src/include/units/pow.h new file mode 100644 index 00000000..81bc9db2 --- /dev/null +++ b/src/include/units/pow.h @@ -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 +#include + +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 +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 diff --git a/src/include/units/quantity.h b/src/include/units/quantity.h index 06c46c5c..fce49bd4 100644 --- a/src/include/units/quantity.h +++ b/src/include/units/quantity.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #if COMP_MSVC || COMP_GCC >= 10 diff --git a/src/include/units/quantity_cast.h b/src/include/units/quantity_cast.h index 42f3118b..d741b319 100644 --- a/src/include/units/quantity_cast.h +++ b/src/include/units/quantity_cast.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -37,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 -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 concept QuantityOf = Quantity && Dimension && equivalent_dim; From ca1867c9b2818c6cbc7790809edd07b6e9f1d548 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johel=20Ernesto=20Guerrero=20Pe=C3=B1a?= Date: Sat, 5 Sep 2020 18:20:19 -0400 Subject: [PATCH 07/22] refactor!: pow functions as detail --- src/include/units/{ => bits}/pow.h | 4 +-- src/include/units/quantity.h | 6 ++-- src/include/units/quantity_cast.h | 50 +++++++++++++++--------------- 3 files changed, 30 insertions(+), 30 deletions(-) rename src/include/units/{ => bits}/pow.h (96%) diff --git a/src/include/units/pow.h b/src/include/units/bits/pow.h similarity index 96% rename from src/include/units/pow.h rename to src/include/units/bits/pow.h index 81bc9db2..c6693103 100644 --- a/src/include/units/pow.h +++ b/src/include/units/bits/pow.h @@ -25,7 +25,7 @@ #include #include -namespace units { +namespace units::detail { constexpr std::intmax_t ipow10(std::intmax_t exp) { @@ -58,4 +58,4 @@ constexpr Rep fpow10(std::intmax_t exp) return result; } -} // namespace units +} // namespace units::detail diff --git a/src/include/units/quantity.h b/src/include/units/quantity.h index fce49bd4..eb38df01 100644 --- a/src/include/units/quantity.h +++ b/src/include/units/quantity.h @@ -25,8 +25,8 @@ #include #include +#include #include -#include #include #if COMP_MSVC || COMP_GCC >= 10 @@ -343,9 +343,9 @@ template) { - return lhs.count() * rhs.count() * static_cast(r.num * fpow10(r.exp)) / static_cast(r.den); + return lhs.count() * rhs.count() * static_cast(r.num * detail::fpow10(r.exp)) / static_cast(r.den); } else { - return lhs.count() * rhs.count() * static_cast(r.num * ipow10(r.exp)) / static_cast(r.den); + return lhs.count() * rhs.count() * static_cast(r.num * detail::ipow10(r.exp)) / static_cast(r.den); } } diff --git a/src/include/units/quantity_cast.h b/src/include/units/quantity_cast.h index d741b319..79509c50 100644 --- a/src/include/units/quantity_cast.h +++ b/src/include/units/quantity_cast.h @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include @@ -63,13 +63,13 @@ struct quantity_cast_impl { static constexpr To cast(const Q& q) { if constexpr (treat_as_floating_point) { - return To(static_cast(static_cast(q.count()) * static_cast(fpow10(CRatio.exp)))); + return To(static_cast(static_cast(q.count()) * static_cast(detail::fpow10(CRatio.exp)))); } else { if constexpr (CRatio.exp > 0) { - return To(static_cast(static_cast(q.count()) * static_cast(ipow10(CRatio.exp)))); + return To(static_cast(static_cast(q.count()) * static_cast(detail::ipow10(CRatio.exp)))); } else { - return To(static_cast(static_cast(q.count()) / static_cast(ipow10(-CRatio.exp)))); + return To(static_cast(static_cast(q.count()) / static_cast(detail::ipow10(-CRatio.exp)))); } } } @@ -93,21 +93,21 @@ struct quantity_cast_impl { { if constexpr (treat_as_floating_point) { return To(static_cast(static_cast(q.count()) * - static_cast(fpow10(CRatio.exp)) * + static_cast(detail::fpow10(CRatio.exp)) * (static_cast(CRatio.num) / static_cast(CRatio.den)))); } else { if constexpr (CRatio.exp > 0) { return To(static_cast(static_cast(q.count()) * static_cast(CRatio.num) * - static_cast(ipow10(CRatio.exp)) / + static_cast(detail::ipow10(CRatio.exp)) / static_cast(CRatio.den))); } else { return To(static_cast(static_cast(q.count()) * static_cast(CRatio.num) / (static_cast(CRatio.den) * - static_cast(ipow10(-CRatio.exp))))); + static_cast(detail::ipow10(-CRatio.exp))))); } } } @@ -128,13 +128,13 @@ struct quantity_cast_impl { static constexpr To cast(const Q& q) { if constexpr (treat_as_floating_point) { - return To(static_cast(static_cast(q.count()) * static_cast(fpow10(CRatio.exp)) * (CRep{1} / static_cast(CRatio.den)))); + return To(static_cast(static_cast(q.count()) * static_cast(detail::fpow10(CRatio.exp)) * (CRep{1} / static_cast(CRatio.den)))); } else { if constexpr (CRatio.exp > 0) { - return To(static_cast(static_cast(q.count()) * static_cast(ipow10(CRatio.exp)) / static_cast(CRatio.den))); + return To(static_cast(static_cast(q.count()) * static_cast(detail::ipow10(CRatio.exp)) / static_cast(CRatio.den))); } else { - return To(static_cast(static_cast(q.count()) / (static_cast(ipow10(-CRatio.exp)) * static_cast(CRatio.den)))); + return To(static_cast(static_cast(q.count()) / (static_cast(detail::ipow10(-CRatio.exp)) * static_cast(CRatio.den)))); } } } @@ -155,13 +155,13 @@ struct quantity_cast_impl { static constexpr To cast(const Q& q) { if constexpr (treat_as_floating_point) { - return To(static_cast(static_cast(q.count()) * static_cast(CRatio.num) * static_cast(fpow10(CRatio.exp)))); + return To(static_cast(static_cast(q.count()) * static_cast(CRatio.num) * static_cast(detail::fpow10(CRatio.exp)))); } else { if constexpr (CRatio.exp > 0) { - return To(static_cast(static_cast(q.count()) * static_cast(CRatio.num) * static_cast(ipow10(CRatio.exp)))); + return To(static_cast(static_cast(q.count()) * static_cast(CRatio.num) * static_cast(detail::ipow10(CRatio.exp)))); } else { - return To(static_cast(static_cast(q.count()) * static_cast(CRatio.num) / static_cast(ipow10(-CRatio.exp)))); + return To(static_cast(static_cast(q.count()) * static_cast(CRatio.num) / static_cast(detail::ipow10(-CRatio.exp)))); } } } @@ -173,13 +173,13 @@ struct quantity_cast_impl { static constexpr To cast(const Q& q) { if constexpr (treat_as_floating_point) { - return To(static_cast(q.count() * fpow10(CRatio.exp))); + return To(static_cast(q.count() * detail::fpow10(CRatio.exp))); } else { if constexpr (CRatio.exp > 0) { - return To(static_cast(q.count() * ipow10(CRatio.exp))); + return To(static_cast(q.count() * detail::ipow10(CRatio.exp))); } else { - return To(static_cast(q.count() / ipow10(-CRatio.exp))); + return To(static_cast(q.count() / detail::ipow10(-CRatio.exp))); } } } @@ -200,13 +200,13 @@ struct quantity_cast_impl { static constexpr To cast(const Q& q) { if constexpr (treat_as_floating_point) { - return To(static_cast(q.count() * fpow10(CRatio.exp) * (CRatio.num / CRatio.den))); + return To(static_cast(q.count() * detail::fpow10(CRatio.exp) * (CRatio.num / CRatio.den))); } else { if constexpr (CRatio.exp > 0) { - return To(static_cast(q.count() * CRatio.num * ipow10(CRatio.exp) / CRatio.den)); + return To(static_cast(q.count() * CRatio.num * detail::ipow10(CRatio.exp) / CRatio.den)); } else { - return To(static_cast(q.count()) * CRatio.num / (CRatio.den * ipow10(-CRatio.exp))); + return To(static_cast(q.count()) * CRatio.num / (CRatio.den * detail::ipow10(-CRatio.exp))); } } } @@ -227,13 +227,13 @@ struct quantity_cast_impl { static constexpr To cast(const Q& q) { if constexpr (treat_as_floating_point) { - return To(static_cast(q.count() * fpow10(CRatio.exp) / CRatio.den)); + return To(static_cast(q.count() * detail::fpow10(CRatio.exp) / CRatio.den)); } else { if constexpr (CRatio.exp > 0) { - return To(static_cast(q.count() * ipow10(CRatio.exp) / CRatio.den)); + return To(static_cast(q.count() * detail::ipow10(CRatio.exp) / CRatio.den)); } else { - return To(static_cast(q.count() / (ipow10(-CRatio.exp) * CRatio.den))); + return To(static_cast(q.count() / (detail::ipow10(-CRatio.exp) * CRatio.den))); } } } @@ -254,13 +254,13 @@ struct quantity_cast_impl { static constexpr To cast(const Q& q) { if constexpr (treat_as_floating_point) { - return To(static_cast(q.count() * CRatio.num * fpow10(CRatio.exp))); + return To(static_cast(q.count() * CRatio.num * detail::fpow10(CRatio.exp))); } else { if constexpr (CRatio.exp > 0) { - return To(static_cast(q.count() * CRatio.num * ipow10(CRatio.exp))); + return To(static_cast(q.count() * CRatio.num * detail::ipow10(CRatio.exp))); } else { - return To(static_cast(q.count() * CRatio.num / ipow10(-CRatio.exp))); + return To(static_cast(q.count() * CRatio.num / detail::ipow10(-CRatio.exp))); } } } From 9f9397ffc285a354a136f46b013e3e3270b885d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johel=20Ernesto=20Guerrero=20Pe=C3=B1a?= Date: Sat, 5 Sep 2020 21:41:02 -0400 Subject: [PATCH 08/22] test: convert comments to code --- test/unit_test/static/quantity_point_test.cpp | 2 +- test/unit_test/static/quantity_test.cpp | 73 ++++++++++++------- 2 files changed, 47 insertions(+), 28 deletions(-) diff --git a/test/unit_test/static/quantity_point_test.cpp b/test/unit_test/static/quantity_point_test.cpp index 424d785f..c03ba222 100644 --- a/test/unit_test/static/quantity_point_test.cpp +++ b/test/unit_test/static/quantity_point_test.cpp @@ -47,7 +47,7 @@ concept invalid_types = requires !requires { typename quantity; }; // reordered arguments }; -static_assert(invalid_types); +static_assert(invalid_types); // member types diff --git a/test/unit_test/static/quantity_test.cpp b/test/unit_test/static/quantity_test.cpp index 3e4b20f4..3e80b688 100644 --- a/test/unit_test/static/quantity_test.cpp +++ b/test/unit_test/static/quantity_test.cpp @@ -36,11 +36,18 @@ using namespace units::physical::si; // class invariants -// constexpr quantity error(0); // should not compile (unit of a different dimension) -// constexpr quantity> error(0); // should not compile (quantity used as Rep) -// constexpr quantity error(0); // should not compile (reordered arguments) // constexpr quantity, int> error(0); // should not compile (negative unit ratio) +template +concept invalid_types = requires +{ + !requires { typename quantity; }; // unit of a different dimension + !requires { typename quantity>; }; // quantity used as Rep + !requires { typename quantity; }; // reordered arguments +}; + +static_assert(invalid_types); + // member types static_assert(is_same_v::rep, int>); @@ -56,18 +63,21 @@ static_assert(km.count() == 1000); static_assert(length(km).count() == km.count()); static_assert(length(1).count() == 1); -// static_assert(length(1.0).count() == 1); // should not compile (truncating conversion) +static_assert(!std::is_constructible_v, double>); // truncating conversion static_assert(length(1.0).count() == 1.0); static_assert(length(1).count() == 1.0); static_assert(length(3.14).count() == 3.14); static_assert(length(km).count() == 1000); -// static_assert(length(length(3.14)).count() == 3); // should not compile (truncating conversion) +static_assert(!std::is_constructible_v, + length>); // truncating conversion static_assert(length(1000.0q_m).count() == 1000.0); static_assert(length(km).count() == 1000.0); static_assert(length(1q_km).count() == 1000); -// static_assert(length(1q_s).count() == 1); // should not compile (different dimensions) -//static_assert(length(1010q_m).count() == 1); // should not compile (truncating conversion) +static_assert(!std::is_constructible_v, + physical::si::time>); // different dimensions +static_assert(!std::is_constructible_v, + length>); // truncating conversion // assignment operator @@ -89,24 +99,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(1001), length(1000))); + return std::pair(v, vv); +}(km) == std::pair(length(1001), length(1000))); static_assert([](auto v) { auto vv = ++v; - return std::make_pair(v, vv); -}(km) == std::make_pair(length(1001), length(1001))); + return std::pair(v, vv); +}(km) == std::pair(length(1001), length(1001))); static_assert([](auto v) { auto vv = v--; - return std::make_pair(v, vv); -}(km) == std::make_pair(length(999), length(1000))); + return std::pair(v, vv); +}(km) == std::pair(length(999), length(1000))); static_assert([](auto v) { auto vv = --v; - return std::make_pair(v, vv); -}(km) == std::make_pair(length(999), length(999))); + return std::pair(v, vv); +}(km) == std::pair(length(999), length(999))); // compound assignment @@ -116,22 +124,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 +concept invalid_compound_assignments = requires() +{ + !requires(length l) { l %= 2.; }; + !requires(length l) { l %= 2; }; + !requires(length l) { l %= 2.; }; + !requires(length l) { l %= 2.q_m; }; + !requires(length l) { l %= 2q_m; }; + !requires(length l) { l %= 2.q_m; }; + !requires(length l) { l += 3.5q_m; }; + !requires(length l) { l *= 3.5q_m; }; +}; + +static_assert(invalid_compound_assignments); + // non-member arithmetic operators static_assert(is_same_v() + length()), length>); @@ -253,9 +268,13 @@ static_assert(quantity_cast(1.23q_m).count() == 1); // time -// static_assert(1q_s == 1q_m); // should not compile (different dimensions) static_assert(1q_h == 3600q_s); +template +constexpr bool no_crossdimensional_equality = !requires { 1q_s == length(1); }; + +static_assert(no_crossdimensional_equality); + // length static_assert(1q_km == 1000q_m); From 71eda2fc66724e3e5a28e3bd71b4bbb37da22aa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johel=20Ernesto=20Guerrero=20Pe=C3=B1a?= Date: Sat, 5 Sep 2020 22:22:18 -0400 Subject: [PATCH 09/22] test: codify comment in the correct place --- test/unit_test/static/quantity_test.cpp | 2 -- test/unit_test/static/unit_test.cpp | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/test/unit_test/static/quantity_test.cpp b/test/unit_test/static/quantity_test.cpp index 3e80b688..dcc9d7bf 100644 --- a/test/unit_test/static/quantity_test.cpp +++ b/test/unit_test/static/quantity_test.cpp @@ -36,8 +36,6 @@ using namespace units::physical::si; // class invariants -// constexpr quantity, int> error(0); // should not compile (negative unit ratio) - template concept invalid_types = requires { diff --git a/test/unit_test/static/unit_test.cpp b/test/unit_test/static/unit_test.cpp index a48a1e86..125db502 100644 --- a/test/unit_test/static/unit_test.cpp +++ b/test/unit_test/static/unit_test.cpp @@ -51,6 +51,9 @@ static_assert(is_same_v>, centimetr static_assert(is_same_v>, yard>); static_assert(is_same_v>, foot>); static_assert(is_same_v>, kilometre_per_hour>); +#if COMP_MSVC || COMP_GCC >= 10 +static_assert([]() { return !requires { typename scaled_unit; }; }.template operator()()); // negative unit ratio +#endif static_assert(centimetre::symbol == "cm"); static_assert(kilometre::symbol == "km"); From 45cf2dcf885428013cf2635c3a3d4279105173a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johel=20Ernesto=20Guerrero=20Pe=C3=B1a?= Date: Sat, 5 Sep 2020 22:39:25 -0400 Subject: [PATCH 10/22] test: remove outdated comment --- test/unit_test/static/ratio_test.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/test/unit_test/static/ratio_test.cpp b/test/unit_test/static/ratio_test.cpp index 2c05828b..4284439c 100644 --- a/test/unit_test/static/ratio_test.cpp +++ b/test/unit_test/static/ratio_test.cpp @@ -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)); From aff83b31dc56ac3d14f648bf893470a062706364 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johel=20Ernesto=20Guerrero=20Pe=C3=B1a?= Date: Sat, 5 Sep 2020 22:39:34 -0400 Subject: [PATCH 11/22] test: codify comment --- test/unit_test/static/unit_test.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/unit_test/static/unit_test.cpp b/test/unit_test/static/unit_test.cpp index 125db502..23ca50d6 100644 --- a/test/unit_test/static/unit_test.cpp +++ b/test/unit_test/static/unit_test.cpp @@ -40,6 +40,9 @@ struct hour : named_scaled_unit { struct dim_time : base_dimension<"time", second> {}; struct kelvin : named_unit {}; +#if COMP_MSVC || COMP_GCC >= 10 +static_assert([]() { return !requires { typename prefixed_unit; }; }.template operator()()); // negative unit ratio +#endif // struct kilokelvin : prefixed_unit {}; // should not compile (prefix not allowed for this reference unit) struct metre_per_second : unit {}; From 4aeb9d305ac76cbe719f8a4294b397385bc85b67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johel=20Ernesto=20Guerrero=20Pe=C3=B1a?= Date: Sat, 5 Sep 2020 22:53:19 -0400 Subject: [PATCH 12/22] test: what we mean a concept can fail for whatever requirement, and maybe the "main" one actually works (== in this case) --- test/unit_test/static/quantity_point_test.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/test/unit_test/static/quantity_point_test.cpp b/test/unit_test/static/quantity_point_test.cpp index c03ba222..48267bfc 100644 --- a/test/unit_test/static/quantity_point_test.cpp +++ b/test/unit_test/static/quantity_point_test.cpp @@ -226,12 +226,16 @@ static_assert(quantity_point_cast(quantity_point(1.23q_m)).relative().count // time -#if COMP_MSVC || COMP_GCC >= 10 -static_assert(!std::equality_comparable_with, - quantity_point>); // different dimensions -#endif static_assert(quantity_point{1q_h} == quantity_point{3600q_s}); +template +constexpr bool no_crossdimensional_equality = !requires +{ + quantity_point(1q_s) == quantity_point(length(1)); +}; + +static_assert(no_crossdimensional_equality); + // length static_assert(quantity_point(1q_km) == quantity_point(1000q_m)); From 36046fb6a6bc6a733e2807779cfd4c6f82b051c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johel=20Ernesto=20Guerrero=20Pe=C3=B1a?= Date: Sat, 5 Sep 2020 22:55:59 -0400 Subject: [PATCH 13/22] test: simplify case --- test/unit_test/static/unit_test.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/unit_test/static/unit_test.cpp b/test/unit_test/static/unit_test.cpp index 23ca50d6..f13d0ac6 100644 --- a/test/unit_test/static/unit_test.cpp +++ b/test/unit_test/static/unit_test.cpp @@ -41,9 +41,8 @@ struct dim_time : base_dimension<"time", second> {}; struct kelvin : named_unit {}; #if COMP_MSVC || COMP_GCC >= 10 -static_assert([]() { return !requires { typename prefixed_unit; }; }.template operator()()); // negative unit ratio +static_assert([](P) { return !requires { typename prefixed_unit; }; }(si::kilo{})); // negative unit ratio #endif -// struct kilokelvin : prefixed_unit {}; // should not compile (prefix not allowed for this reference unit) struct metre_per_second : unit {}; struct dim_speed : derived_dimension, units::exp> {}; From 411241472992301f14da30471a89618bce62c5f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johel=20Ernesto=20Guerrero=20Pe=C3=B1a?= Date: Sun, 6 Sep 2020 01:10:11 -0400 Subject: [PATCH 14/22] test: nonzero denominator --- test/unit_test/static/ratio_test.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/unit_test/static/ratio_test.cpp b/test/unit_test/static/ratio_test.cpp index 4284439c..4b4d044f 100644 --- a/test/unit_test/static/ratio_test.cpp +++ b/test/unit_test/static/ratio_test.cpp @@ -88,4 +88,10 @@ static_assert(common_ratio(ratio(100, 1), ratio(1, 10)) == ratio(1, 10)); static_assert(common_ratio(ratio(1), ratio(1, 1, 3)) == ratio(1)); static_assert(common_ratio(ratio(10, 1, -1), ratio(1, 1, -3)) == ratio(1, 1, -3)); +// nonzero denominator +template struct require_constant; // [range.split.view] +template concept constant = requires { typename require_constant; }; + +static_assert(!constant<[] { ratio(1, 0); }>); + } // namespace From c09dbb1756ab8cb9323be4cc163e8c2cb838090e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johel=20Ernesto=20Guerrero=20Pe=C3=B1a?= Date: Sun, 6 Sep 2020 01:33:47 -0400 Subject: [PATCH 15/22] test: add missing explicit specifier --- test/unit_test/static/custom_rep_min_req_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit_test/static/custom_rep_min_req_test.cpp b/test/unit_test/static/custom_rep_min_req_test.cpp index d9a12ce5..8f7783b8 100644 --- a/test/unit_test/static/custom_rep_min_req_test.cpp +++ b/test/unit_test/static/custom_rep_min_req_test.cpp @@ -65,7 +65,7 @@ template struct expl_constructible : scalar_ops> { 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 }; From f1f23aa8f9d2fa8157620334721c5e38f38d0805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johel=20Ernesto=20Guerrero=20Pe=C3=B1a?= Date: Sun, 6 Sep 2020 03:00:33 -0400 Subject: [PATCH 16/22] test: codify comments --- .../static/custom_rep_min_req_test.cpp | 69 ++++++++++--------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/test/unit_test/static/custom_rep_min_req_test.cpp b/test/unit_test/static/custom_rep_min_req_test.cpp index 8f7783b8..2f50c244 100644 --- a/test/unit_test/static/custom_rep_min_req_test.cpp +++ b/test/unit_test/static/custom_rep_min_req_test.cpp @@ -25,6 +25,7 @@ #include "units/physical/si/frequency.h" #include "units/physical/si/speed.h" #include +#include #include using namespace units; @@ -172,60 +173,60 @@ using namespace units::physical::si; // Quantity from Scalar // int <- int static_assert(length(expl_impl(1)).count() == 1); -// static_assert(length(impl_expl(1)).count() == 1); // should not compile (not convertible) +static_assert(!std::is_constructible_v, impl_expl>); static_assert(length(int(impl_expl(1))).count() == 1); -// static_assert(length>(1).count() == expl_impl{1}); // should not compile (not convertible) +static_assert(!std::is_constructible_v>, int>); static_assert(length>(expl_impl(1)).count() == expl_impl{1}); static_assert(length>(1).count() == impl_expl{1}); // double <- double static_assert(length(expl_impl(1.0)).count() == 1.0); -// static_assert(length(impl_expl(1.0)).count() == 1.0); // should not compile (not convertible) +static_assert(!std::is_constructible_v, impl_expl>); static_assert(length(double(impl_expl(1.0))).count() == 1.0); -// static_assert(length>(1.0).count() == expl_impl{1.0}); // should not compile (not convertible) +static_assert(!std::is_constructible_v>, double>); static_assert(length>(expl_impl(1.0)).count() == expl_impl{1.0}); static_assert(length>(1.0).count() == impl_expl{1.0}); // double <- int static_assert(length(expl_impl(1)).count() == 1.0); -// static_assert(length(impl_expl(1)).count() == 1.0); // should not compile (not convertible) +static_assert(!std::is_constructible_v, impl_expl>); static_assert(length(int(impl_expl(1))).count() == 1.0); -// static_assert(length>(1).count() == expl_impl{1}); // should not compile (not convertible) +static_assert(!std::is_constructible_v>, int>); static_assert(length>(expl_impl(1)).count() == expl_impl{1}); static_assert(length>(1).count() == impl_expl{1.0}); // int <- double -// static_assert(length(expl_impl(1.0)).count() == 1); // should not compile (truncating conversion) -// static_assert(length>(1.0).count() == impl_expl{1}); // should not compile (truncating conversion) +static_assert(!std::is_constructible_v, expl_impl>); +static_assert(!std::is_constructible_v>, double>); // Quantity from other Quantity with different Rep // int <- int static_assert(length(length>(expl_impl(1))).count() == 1); -// static_assert(length(length>(1)).count() == 1); // should not compile (not convertible) +static_assert(!std::is_constructible_v, length>>); static_assert(length(quantity_cast(length>(1))).count() == 1); -// static_assert(length>(length(1)).count() == expl_impl{1}); // should not compile (not convertible) +static_assert(!std::is_constructible_v>, length>); static_assert(length>(quantity_cast>(length(1))).count() == expl_impl{1}); static_assert(length>(length(1)).count() == impl_expl{1}); // double <- double static_assert(length(length>(expl_impl(1.0))).count() == 1.0); -// static_assert(length(length>(1.0)).count() == 1.0); // should not compile (not convertible) +static_assert(!std::is_constructible_v, length>>); static_assert(length(quantity_cast(length>(1.0))).count() == 1.0); -// static_assert(length>(length(1.0).count() == expl_impl{1.0}); // should not compile (not convertible) +static_assert(!std::is_constructible_v>, length>); static_assert(length>(quantity_cast>(length(1.0))).count() == expl_impl{1.0}); static_assert(length>(length(1.0)).count() == impl_expl{1.0}); // double <- int static_assert(length(length>(expl_impl(1))).count() == 1.0); -// static_assert(length(length>(1)).count() == 1.0); // should not compile (not convertible) +static_assert(!std::is_constructible_v, length>>); static_assert(length(quantity_cast(length>(1))).count() == 1.0); -// static_assert(length>(length(1)).count() == expl_impl{1}); // should not compile (not convertible) +static_assert(!std::is_constructible_v>, length>); static_assert(length>(quantity_cast>(length(1))).count() == expl_impl{1}); static_assert(length>(length(1)).count() == impl_expl{1.0}); // int <- double -// static_assert(length(length>(1.0)).count() == 1); // should not compile (truncating conversion) -// static_assert(length>(length(1.0)).count() == impl_expl{1}); // should not compile (truncating conversion) +static_assert(!std::is_constructible_v, length>>); +static_assert(!std::is_constructible_v>, length>); // unit conversions @@ -236,43 +237,43 @@ static_assert(length>(length>(1) static_assert(length>(length>(expl_impl(1))).count() == expl_impl(1000)); static_assert(length>(length>(expl_expl(1))).count() == expl_expl(1000)); -// static_assert(length>(length>(2000)).count() == impl(2)); // should not compile (truncating conversion) +static_assert(!std::is_constructible_v>, length>>); static_assert(length>(quantity_cast(length>(2000))).count() == impl(2)); -// static_assert(length>(length>(expl(2000))).count() == expl(2)); // should not compile (truncating conversion) +static_assert(!std::is_constructible_v>, length>>); static_assert(length>(quantity_cast(length>(expl(2000)))).count() == expl(2)); -// static_assert(length>(length>(2000)).count() == impl_impl(2)); // should not compile (truncating conversion) +static_assert(!std::is_constructible_v>, length>>); static_assert(length>(quantity_cast(length>(2000))).count() == impl_impl(2)); -// static_assert(length>(length>(2000)).count() == impl_expl(2)); // should not compile (truncating conversion) +static_assert(!std::is_constructible_v>, length>>); static_assert(length>(quantity_cast(length>(2000))).count() == impl_expl(2)); -// static_assert(length>(length>(expl_impl(2000))).count() == expl_impl(2)); // should not compile (truncating conversion) +static_assert(!std::is_constructible_v>, length>>); static_assert(length>(quantity_cast(length>(expl_impl(2000)))).count() == expl_impl(2)); -// static_assert(length>(length>(expl_expl(2000))).count() == expl_expl(2)); // should not compile (truncating conversion) +static_assert(!std::is_constructible_v>, length>>); static_assert(length>(quantity_cast(length>(expl_expl(2000)))).count() == expl_expl(2)); -// static_assert(speed>(speed>(72)).count() == impl(20)); // should not compile (truncating conversion) +static_assert(!std::is_constructible_v>, speed>>); static_assert(speed>(quantity_cast(speed>(72))).count() == impl(20)); -// static_assert(speed>(speed>(expl(72))).count() == expl(20)); // should not compile (truncating conversion) +static_assert(!std::is_constructible_v>, speed>>); static_assert(speed>(quantity_cast(speed>(expl(72)))).count() == expl(20)); -// static_assert(speed>(speed>(72)).count() == impl_impl(20)); // should not compile (truncating conversion) +static_assert(!std::is_constructible_v>, speed>>); static_assert(speed>(quantity_cast(speed>(72))).count() == impl_impl(20)); -// static_assert(speed>(speed>(72)).count() == impl_expl(20)); // should not compile (truncating conversion) +static_assert(!std::is_constructible_v>, speed>>); static_assert(speed>(quantity_cast(speed>(72))).count() == impl_expl(20)); -// static_assert(speed>(speed>(expl_impl(72))).count() == expl_impl(20)); // should not compile (truncating conversion) +static_assert(!std::is_constructible_v>, speed>>); static_assert(speed>(quantity_cast(speed>(expl_impl(72)))).count() == expl_impl(20)); -// static_assert(speed>(speed>(expl_expl(72))).count() == expl_expl(20)); // should not compile (truncating conversion) +static_assert(!std::is_constructible_v>, speed>>); static_assert(speed>(quantity_cast(speed>(expl_expl(72)))).count() == expl_expl(20)); -// static_assert(speed>(speed>(20)).count() == impl(72)); // should not compile (truncating conversion) +static_assert(!std::is_constructible_v>, speed>>); static_assert(speed>(quantity_cast(speed>(20))).count() == impl(72)); -// static_assert(speed>(speed>(expl(20))).count() == expl(72)); // should not compile (truncating conversion) +static_assert(!std::is_constructible_v>, speed>>); static_assert(speed>(quantity_cast(speed>(expl(20)))).count() == expl(72)); -// static_assert(speed>(speed>(20)).count() == impl_impl(72)); // should not compile (truncating conversion) +static_assert(!std::is_constructible_v>, speed>>); static_assert(speed>(quantity_cast(speed>(20))).count() == impl_impl(72)); -// static_assert(speed>(speed>(20)).count() == impl_expl(72)); // should not compile (truncating conversion) +static_assert(!std::is_constructible_v>, speed>>); static_assert(speed>(quantity_cast(speed>(20))).count() == impl_expl(72)); -// static_assert(speed>(speed>(expl_impl(20))).count() == expl_impl(72)); // should not compile (truncating conversion) +static_assert(!std::is_constructible_v>, speed>>); static_assert(speed>(quantity_cast(speed>(expl_impl(20)))).count() == expl_impl(72)); -// static_assert(speed>(speed>(expl_expl(20))).count() == expl_expl(72)); // should not compile (truncating conversion) +static_assert(!std::is_constructible_v>, speed>>); static_assert(speed>(quantity_cast(speed>(expl_expl(20)))).count() == expl_expl(72)); } // namespace From d03d7291e4f1c4cbf8eb441c37f4f636c38a8953 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Sun, 6 Sep 2020 10:23:31 +0200 Subject: [PATCH 17/22] Removed cmake/common submodule --- .gitmodules | 3 - CMakeLists.txt | 2 +- cmake/common | 1 - cmake/common/conan.cmake | 46 ++++++++++++ cmake/common/install.cmake | 81 ++++++++++++++++++++ cmake/common/scripts.cmake | 28 +++++++ cmake/common/simple-config.cmake.in | 1 + cmake/common/static_analysis.cmake | 44 +++++++++++ cmake/common/warnings.cmake | 110 ++++++++++++++++++++++++++++ docs/usage.rst | 6 +- src/CMakeLists.txt | 4 +- 11 files changed, 316 insertions(+), 10 deletions(-) delete mode 100644 .gitmodules delete mode 160000 cmake/common create mode 100644 cmake/common/conan.cmake create mode 100644 cmake/common/install.cmake create mode 100644 cmake/common/scripts.cmake create mode 100644 cmake/common/simple-config.cmake.in create mode 100644 cmake/common/static_analysis.cmake create mode 100644 cmake/common/warnings.cmake diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index cafa8d43..00000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "cmake/common"] - path = cmake/common - url = https://github.com/mpusz/cmake-scripts.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 08831032..b18a30a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/cmake/common b/cmake/common deleted file mode 160000 index b951a327..00000000 --- a/cmake/common +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b951a32791923f22f9992fc297c111e472c93a4f diff --git a/cmake/common/conan.cmake b/cmake/common/conan.cmake new file mode 100644 index 00000000..6219e05c --- /dev/null +++ b/cmake/common/conan.cmake @@ -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() diff --git a/cmake/common/install.cmake b/cmake/common/install.cmake new file mode 100644 index 00000000..49f9c7e1 --- /dev/null +++ b/cmake/common/install.cmake @@ -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() diff --git a/cmake/common/scripts.cmake b/cmake/common/scripts.cmake new file mode 100644 index 00000000..b3ea4224 --- /dev/null +++ b/cmake/common/scripts.cmake @@ -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) diff --git a/cmake/common/simple-config.cmake.in b/cmake/common/simple-config.cmake.in new file mode 100644 index 00000000..f40ebfa8 --- /dev/null +++ b/cmake/common/simple-config.cmake.in @@ -0,0 +1 @@ +include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake") diff --git a/cmake/common/static_analysis.cmake b/cmake/common/static_analysis.cmake new file mode 100644 index 00000000..99c2c9f2 --- /dev/null +++ b/cmake/common/static_analysis.cmake @@ -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() diff --git a/cmake/common/warnings.cmake b/cmake/common/warnings.cmake new file mode 100644 index 00000000..c60a5c8c --- /dev/null +++ b/cmake/common/warnings.cmake @@ -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() diff --git a/docs/usage.rst b/docs/usage.rst index f11d87bf..f7b703b4 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -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:: diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 23332d47..832cc02c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -31,7 +31,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) @@ -103,4 +103,4 @@ install(DIRECTORY include/units ) # generate configuration files and install the package -configure_and_install(../cmake/common/cmake/simple-config.cmake.in mp-units SameMajorVersion) +configure_and_install(../cmake/common/simple-config.cmake.in mp-units SameMajorVersion) From 44b54c290d4ccbade8b679e88a580c0b56493045 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Sun, 6 Sep 2020 12:36:49 +0200 Subject: [PATCH 18/22] test_package fixed --- test_package/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_package/CMakeLists.txt b/test_package/CMakeLists.txt index b59831c0..ce6a5c40 100644 --- a/test_package/CMakeLists.txt +++ b/test_package/CMakeLists.txt @@ -27,7 +27,7 @@ project(test_package) 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) From 95410ab49bbfe31d9720f37508fccbd713fdabef Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Sun, 6 Sep 2020 14:54:37 +0200 Subject: [PATCH 19/22] bincrafters conan remote removed from build.py --- build.py | 1 - 1 file changed, 1 deletion(-) diff --git a/build.py b/build.py index f060a37f..cffae86b 100644 --- a/build.py +++ b/build.py @@ -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"], From 77e11173bf30149542397c91d26235111cfc37e7 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Sun, 6 Sep 2020 15:35:08 +0200 Subject: [PATCH 20/22] Unit tests compilation fixed on VS --- test/unit_test/static/quantity_point_test.cpp | 3 ++- test/unit_test/static/quantity_test.cpp | 2 +- test/unit_test/static/unit_test.cpp | 8 +++++--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/test/unit_test/static/quantity_point_test.cpp b/test/unit_test/static/quantity_point_test.cpp index 48267bfc..b440a6cc 100644 --- a/test/unit_test/static/quantity_point_test.cpp +++ b/test/unit_test/static/quantity_point_test.cpp @@ -229,7 +229,7 @@ static_assert(quantity_point_cast(quantity_point(1.23q_m)).relative().count static_assert(quantity_point{1q_h} == quantity_point{3600q_s}); template -constexpr bool no_crossdimensional_equality = !requires +concept no_crossdimensional_equality = !requires { quantity_point(1q_s) == quantity_point(length(1)); }; @@ -238,6 +238,7 @@ static_assert(no_crossdimensional_equality); // 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)); diff --git a/test/unit_test/static/quantity_test.cpp b/test/unit_test/static/quantity_test.cpp index dcc9d7bf..eaf4832a 100644 --- a/test/unit_test/static/quantity_test.cpp +++ b/test/unit_test/static/quantity_test.cpp @@ -269,7 +269,7 @@ static_assert(quantity_cast(1.23q_m).count() == 1); static_assert(1q_h == 3600q_s); template -constexpr bool no_crossdimensional_equality = !requires { 1q_s == length(1); }; +concept no_crossdimensional_equality = !requires { 1q_s == length(1); }; static_assert(no_crossdimensional_equality); diff --git a/test/unit_test/static/unit_test.cpp b/test/unit_test/static/unit_test.cpp index f13d0ac6..b0c90abf 100644 --- a/test/unit_test/static/unit_test.cpp +++ b/test/unit_test/static/unit_test.cpp @@ -40,8 +40,9 @@ struct hour : named_scaled_unit { struct dim_time : base_dimension<"time", second> {}; struct kelvin : named_unit {}; -#if COMP_MSVC || COMP_GCC >= 10 -static_assert([](P) { return !requires { typename prefixed_unit; }; }(si::kilo{})); // negative unit ratio + +#if COMP_GCC >= 10 +static_assert([](P) { return !requires { typename prefixed_unit; }; }(si::kilo{})); // no prefix allowed #endif struct metre_per_second : unit {}; @@ -53,7 +54,8 @@ static_assert(is_same_v>, centimetr static_assert(is_same_v>, yard>); static_assert(is_same_v>, foot>); static_assert(is_same_v>, kilometre_per_hour>); -#if COMP_MSVC || COMP_GCC >= 10 + +#if COMP_GCC >= 10 static_assert([]() { return !requires { typename scaled_unit; }; }.template operator()()); // negative unit ratio #endif From cacd3ae543b1718d9fa8004b8a23a9dc13e6189c Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Sun, 6 Sep 2020 15:35:52 +0200 Subject: [PATCH 21/22] Non-zero denominator contract added for ratio --- src/include/units/ratio.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/include/units/ratio.h b/src/include/units/ratio.h index 2a483a46..c21f196c 100644 --- a/src/include/units/ratio.h +++ b/src/include/units/ratio.h @@ -29,6 +29,7 @@ #include #include #include +#include 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); } From 73636cbb8e5822a311c4165d3db37b369b711676 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Sun, 6 Sep 2020 15:36:04 +0200 Subject: [PATCH 22/22] Invalid test removed --- test/unit_test/static/ratio_test.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/test/unit_test/static/ratio_test.cpp b/test/unit_test/static/ratio_test.cpp index 4b4d044f..4284439c 100644 --- a/test/unit_test/static/ratio_test.cpp +++ b/test/unit_test/static/ratio_test.cpp @@ -88,10 +88,4 @@ static_assert(common_ratio(ratio(100, 1), ratio(1, 10)) == ratio(1, 10)); static_assert(common_ratio(ratio(1), ratio(1, 1, 3)) == ratio(1)); static_assert(common_ratio(ratio(10, 1, -1), ratio(1, 1, -3)) == ratio(1, 1, -3)); -// nonzero denominator -template struct require_constant; // [range.split.view] -template concept constant = requires { typename require_constant; }; - -static_assert(!constant<[] { ratio(1, 0); }>); - } // namespace