diff --git a/.clang-format b/.clang-format index b37a7280..4779d2b2 100644 --- a/.clang-format +++ b/.clang-format @@ -52,7 +52,7 @@ BreakConstructorInitializersBeforeComma: true BreakInheritanceList: AfterColon # BreakStringLiterals: true ColumnLimit: 120 -# CommentPragmas: '^ IWYU pragma:' +CommentPragmas: '^ NOLINT' # CompactNamespaces: false # ConstructorInitializerAllOnOneLineOrOnePerLine: true # ConstructorInitializerIndentWidth: 4 diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 00000000..9e1c87bc --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,23 @@ +--- +Checks: ' + *, + -llvm-header-guard, + -llvm-include-order, + -bugprone-branch-clone, + -bugprone-reserved-identifier, + -modernize-use-trailing-return-type, + -fuchsia-default-arguments-calls, + -fuchsia-overloaded-operator, + -fuchsia-statically-constructed-objects, + -fuchsia-trailing-return, + -*-special-member-functions, + -cppcoreguidelines-owning-memory, + -cert-err58-cpp, + -cert-dcl37-c, + -cert-dcl51-cpp +' +WarningsAsErrors: '*' +HeaderFilterRegex: '.*' +AnalyzeTemporaryDtors: false +FormatStyle: file +... diff --git a/CMakeLists.txt b/CMakeLists.txt index 863addb5..93d850e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,19 +27,24 @@ project(units) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") # include common tools and workarounds -include(common/cmake/tools) +include(common/cmake/scripts) # use Conan configuration if available conan_init(cmake) -# compilation options and flags used in a project development process -include(common/cmake/compile_flags) +# enable static analysis +#enable_clang_tidy() +#enable_iwyu() + +# set restrictive compilation warnings +set_warnings(TREAT_AS_ERRORS) # add project code add_subdirectory(src) -# add unit tests -add_subdirectory(test) - # add usage example add_subdirectory(example) + +# add unit tests +enable_testing() +add_subdirectory(test) diff --git a/cmake/common b/cmake/common index fa85aebd..7c44183e 160000 --- a/cmake/common +++ b/cmake/common @@ -1 +1 @@ -Subproject commit fa85aebdd45ce88e6c2d72dedc8e1693dc419f67 +Subproject commit 7c44183e57ac009acb41e40e831b86b8e5d4a122 diff --git a/conanfile.py b/conanfile.py index e0d69493..02a96c8e 100644 --- a/conanfile.py +++ b/conanfile.py @@ -21,15 +21,14 @@ # SOFTWARE. from conans import ConanFile, CMake, tools -from conans.tools import load, Version +from conans.tools import Version from conans.errors import ConanInvalidConfiguration import re -import os def get_version(): try: - content = load("src/CMakeLists.txt") + content = tools.load("src/CMakeLists.txt") version = re.search(r"project\([^\)]+VERSION (\d+\.\d+\.\d+)[^\)]*\)", content).group(1) return version.strip() except Exception: @@ -44,20 +43,32 @@ class UnitsConan(ConanFile): url = "https://github.com/mpusz/units" description = "Physical Units library for C++" exports = ["LICENSE.md"] - exports_sources = ["src/*", "test/*", "cmake/*", "example/*","CMakeLists.txt"] settings = "os", "compiler", "build_type", "arch" requires = ( "fmt/6.1.0" ) - build_requires = ( - "Catch2/2.11.0@catchorg/stable" - ) + scm = { + "type": "git", + "url": "auto", + "revision": "auto", + "submodule": "recursive" + } generators = "cmake" @property def _run_tests(self): return tools.get_env("CONAN_RUN_TESTS", False) + def _configure_cmake(self, folder="src"): + cmake = CMake(self) + if self._run_tests: + # developer's mode (unit tests, examples, restrictive compilation warnings, ...) + cmake.configure() + else: + # consumer's mode (library sources only) + cmake.configure(source_folder=folder, build_folder=folder) + return cmake + def configure(self): if self.settings.compiler != "gcc": # and self.settings.compiler != "clang": raise ConanInvalidConfiguration("Library works only with gcc") # and clang") @@ -68,23 +79,20 @@ class UnitsConan(ConanFile): if self.settings.compiler.cppstd not in ["20", "gnu20"]: raise ConanInvalidConfiguration("Library requires at least C++20 support") - def _configure_cmake(self, folder="src"): - cmake = CMake(self) - if self._run_tests: - cmake.configure() - else: - cmake.configure(source_folder="src", build_folder="src") - return cmake - def requirements(self): if self.settings.compiler == "clang" or Version(self.settings.compiler.version) < "10": self.requires("range-v3/0.10.0@ericniebler/stable") + def build_requirements(self): + if self._run_tests: + self.build_requires("Catch2/2.11.0@catchorg/stable") + self.build_requires("linear_algebra/0.0.1@public-conan/testing") + def build(self): cmake = self._configure_cmake() cmake.build() if self._run_tests: - self.run(os.path.join("bin", "unit_tests_runtime"), run_environment=True) + self.run("ctest -VV -C %s" % cmake.build_type, run_environment=True) def package(self): self.copy(pattern="LICENSE.md", dst="licenses") @@ -92,7 +100,6 @@ class UnitsConan(ConanFile): cmake.install() def package_info(self): - self.cpp_info.includedirs = ['include'] if self.settings.compiler == "gcc": self.cpp_info.cxxflags = [ "-Wno-literal-suffix", diff --git a/doc/INSTALL.md b/doc/INSTALL.md index a2dc192b..84ece9db 100644 --- a/doc/INSTALL.md +++ b/doc/INSTALL.md @@ -73,15 +73,17 @@ steps may be done: ## Full build and unit testing -In case you would like to build all the code in that repository (with unit tests and examples) -you should use the `CMakeLists.txt` from the parent directory. +In case you would like to build all the code in this repository (with unit tests and examples) +you should use the `CMakeLists.txt` from the parent directory and run Conan with +`CONAN_RUN_TESTS=True`. ```shell git clone --recurse-submodules https://github.com/mpusz/units.git mkdir units/build && cd units/build -conan install .. -s compiler.cppstd=20 -cmake .. +conan install .. -pr -s compiler.cppstd=20 -e CONAN_RUN_TESTS=True -b outdated +cmake .. -DCMAKE_BUILD_TYPE=Release cmake --build . +ctest -VV ``` @@ -90,7 +92,7 @@ cmake --build . To create a `conan` package and test `cmake` installation and `conan` packaging run: ```shell -conan create . / -s cppstd=20 -b=outdated +conan create . / -pr -s compiler.cppstd=20 -e CONAN_RUN_TESTS=True -b outdated ``` diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1c0e8430..3615cf8d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -21,7 +21,6 @@ # SOFTWARE. cmake_minimum_required(VERSION 3.8) -#cmake_policy(SET CMP0076 NEW) project(units VERSION 0.5.0 @@ -32,7 +31,7 @@ project(units list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../cmake") # include common tools and workarounds -include(common/cmake/tools) +include(common/cmake/scripts) # library definition add_library(units INTERFACE) @@ -83,25 +82,14 @@ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") ) endif() endif() - add_library(mp::units ALIAS units) # installation info -install(TARGETS units - EXPORT ${CMAKE_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 - INCLUDES DESTINATION include -) +install_targets(units) install(DIRECTORY include/units DESTINATION include COMPONENT Devel ) -install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/units - DESTINATION include - COMPONENT Devel -) # generate configuration files and install the package -configure_and_install(../cmake/common/cmake/simple_package-config.cmake.in mp SameMajorVersion) +configure_and_install(../cmake/common/cmake/simple-config.cmake.in mp SameMajorVersion) diff --git a/src/include/units/bits/base_units_ratio.h b/src/include/units/bits/base_units_ratio.h index 50d505c5..1d6fbdcd 100644 --- a/src/include/units/bits/base_units_ratio.h +++ b/src/include/units/bits/base_units_ratio.h @@ -33,7 +33,7 @@ template struct exp_ratio { using base_ratio = E::dimension::base_unit::ratio; using positive_ratio = conditional, base_ratio>; - static constexpr std::int64_t N = E::num * E::den < 0 ? -E::num : E::num; + static constexpr std::intmax_t N = E::num * E::den < 0 ? -E::num : E::num; using pow = ratio_pow; using type = conditional, pow>; }; diff --git a/src/include/units/bits/dim_consolidate.h b/src/include/units/bits/dim_consolidate.h index 5a433706..7a5e8057 100644 --- a/src/include/units/bits/dim_consolidate.h +++ b/src/include/units/bits/dim_consolidate.h @@ -54,7 +54,7 @@ struct dim_consolidate> { using type = type_list_push_front>::type, E1>; }; -template +template struct dim_consolidate, exp, ERest...>> { // TODO: provide custom implementation for ratio_add using r1 = std::ratio; diff --git a/src/include/units/bits/dim_unpack.h b/src/include/units/bits/dim_unpack.h index 710ee17b..cdcf9bf4 100644 --- a/src/include/units/bits/dim_unpack.h +++ b/src/include/units/bits/dim_unpack.h @@ -41,17 +41,17 @@ struct dim_unpack<> { using type = exp_list<>; }; -template +template struct dim_unpack, ERest...> { using type = type_list_push_front::type, exp>; }; -template +template struct dim_unpack, ERest...> { using type = dim_unpack, Num, Den>, ERest...>::type; }; -template +template struct dim_unpack, Num, Den>, ERest...> { using type = type_list_push_front::type, exp_multiply...>; }; diff --git a/src/include/units/bits/dimension_op.h b/src/include/units/bits/dimension_op.h index 0405efae..9506cb75 100644 --- a/src/include/units/bits/dimension_op.h +++ b/src/include/units/bits/dimension_op.h @@ -43,7 +43,7 @@ struct equivalent_dim_impl : std::disjunction, equi template struct equivalent_exp : std::false_type {}; -template +template struct equivalent_exp, exp> : equivalent_dim_impl {}; template @@ -230,10 +230,10 @@ using dimension_sqrt = detail::dimension_sqrt_impl::type; // dimension_pow namespace detail { -template +template struct dimension_pow_impl; -template +template struct dimension_pow_impl { using type = downcast_dimension>>; }; @@ -243,24 +243,24 @@ struct dimension_pow_impl { using type = D; }; -template +template struct dimension_pow_impl>, N> { using type = D; }; -template +template struct dimension_pow_impl { using type = dimension_pow_impl, N>::type; }; -template +template struct dimension_pow_impl, N> { using type = downcast_dimension...>>; }; } // namespace detail -template +template using dimension_pow = detail::dimension_pow_impl::type; } // namespace units diff --git a/src/include/units/exp.h b/src/include/units/exp.h index b2d71d67..731187aa 100644 --- a/src/include/units/exp.h +++ b/src/include/units/exp.h @@ -34,7 +34,7 @@ namespace units { * @tparam Num numinator of the factor * @tparam Den denominator of the factor */ -template +template struct exp { using dimension = Dim; static constexpr int num = Num; @@ -44,7 +44,7 @@ struct exp { // is_exp namespace detail { -template +template inline constexpr bool is_exp> = true; } // namespace detail @@ -57,7 +57,7 @@ struct exp_less : base_dimension_less +template constexpr exp exp_invert_impl(exp); } // namespace detail @@ -68,7 +68,7 @@ using exp_invert = decltype(detail::exp_invert_impl(E())); // exp_multiply namespace detail { -template +template struct exp_multiply_impl { using r1 = ratio; using r2 = ratio; @@ -78,7 +78,7 @@ struct exp_multiply_impl { } // namespace detail -template +template using exp_multiply = detail::exp_multiply_impl::type; template diff --git a/src/include/units/format.h b/src/include/units/format.h index 4b361a02..92389236 100644 --- a/src/include/units/format.h +++ b/src/include/units/format.h @@ -199,8 +199,8 @@ private: constexpr void on_minus() { f.specs.sign = fmt::sign::minus; } constexpr void on_space() { f.specs.sign = fmt::sign::space; } constexpr void on_align(align_t align) { f.specs.align = align; } - constexpr void on_width(unsigned width) { f.specs.width = width; } - constexpr void on_precision(unsigned precision) { f.precision = precision; } + constexpr void on_width(int width) { f.specs.width = width; } + constexpr void on_precision(int precision) { f.precision = precision; } constexpr void end_precision() {} template diff --git a/src/include/units/math.h b/src/include/units/math.h index b9782c3f..b4d42429 100644 --- a/src/include/units/math.h +++ b/src/include/units/math.h @@ -27,14 +27,14 @@ namespace units { - template + template requires (N == 0) inline Rep pow(const quantity&) noexcept { return 1; } - template + template inline Quantity AUTO pow(const quantity& q) noexcept { using dim = dimension_pow; diff --git a/src/include/units/quantity_cast.h b/src/include/units/quantity_cast.h index 8d6fd270..6c5c89c7 100644 --- a/src/include/units/quantity_cast.h +++ b/src/include/units/quantity_cast.h @@ -27,7 +27,8 @@ namespace units { -constexpr std::intmax_t ipow10(std::intmax_t exp) { +constexpr std::intmax_t ipow10(std::intmax_t exp) +{ // how to assert here? // static_assert(exp >= 0, "Use fpow10() for negative exponents"); if (exp == 0) return 1; @@ -40,7 +41,8 @@ constexpr std::intmax_t ipow10(std::intmax_t exp) { } -constexpr long double fpow10(std::intmax_t exp) { +constexpr long double fpow10(std::intmax_t exp) +{ if (exp == 0) return 1.0L; long double result = 1.0L; if (exp < 0) { diff --git a/src/include/units/ratio.h b/src/include/units/ratio.h index fd244f7e..49f83603 100644 --- a/src/include/units/ratio.h +++ b/src/include/units/ratio.h @@ -40,7 +40,7 @@ template return v < 0 ? -v : v; } -constexpr std::tuple normalize(std::intmax_t num, std::intmax_t den, std::intmax_t exp) +constexpr std::tuple normalize(std::intmax_t num, std::intmax_t den, std::intmax_t exp) { std::intmax_t gcd = std::gcd(num, den); num = num * (den < 0 ? -1 : 1) / gcd; @@ -100,12 +100,12 @@ namespace detail { static constexpr std::intmax_t safe_multiply(std::intmax_t lhs, std::intmax_t rhs) { - constexpr std::uintmax_t c = std::uintmax_t(1) << (sizeof(std::intmax_t) * 4); + constexpr std::intmax_t c = std::uintmax_t(1) << (sizeof(std::intmax_t) * 4); - const std::uintmax_t a0 = detail::abs(lhs) % c; - const std::uintmax_t a1 = detail::abs(lhs) / c; - const std::uintmax_t b0 = detail::abs(rhs) % c; - const std::uintmax_t b1 = detail::abs(rhs) / c; + const std::intmax_t a0 = detail::abs(lhs) % c; + const std::intmax_t a1 = detail::abs(lhs) / c; + const std::intmax_t b0 = detail::abs(rhs) % c; + const std::intmax_t b1 = detail::abs(rhs) / c; Expects(a1 == 0 || b1 == 0); // overflow in multiplication Expects(a0 * b1 + b0 * a1 < (c >> 1)); // overflow in multiplication @@ -163,7 +163,7 @@ using ratio_divide = detail::ratio_divide_impl::type; namespace detail { -template +template struct ratio_pow_impl { using type = ratio_multiply::type, R>; }; @@ -180,7 +180,7 @@ struct ratio_pow_impl { } // namespace detail -template +template using ratio_pow = detail::ratio_pow_impl::type; // ratio_sqrt diff --git a/test/metabench/make_dimension/dimension_concepts_all.h b/test/metabench/make_dimension/dimension_concepts_all.h index 755da1e1..8278f228 100644 --- a/test/metabench/make_dimension/dimension_concepts_all.h +++ b/test/metabench/make_dimension/dimension_concepts_all.h @@ -62,11 +62,11 @@ namespace units { // exp - template + template struct exp { static constexpr const base_dimension& dimension = BaseDimension; - static constexpr int num = Num; - static constexpr int den = Den; + static constexpr std::intmax_t num = Num; + static constexpr std::intmax_t den = Den; }; // is_exp @@ -74,7 +74,7 @@ namespace units { template inline constexpr bool is_exp = false; - template + template inline constexpr bool is_exp> = true; } // namespace detail @@ -92,7 +92,7 @@ namespace units { template struct exp_invert; - template + template struct exp_invert> { using type = exp; }; @@ -160,7 +160,7 @@ namespace units { using type = conditional>, dimension, type_list_push_front>; }; - template + template struct dim_consolidate, exp, ERest...>> { using r1 = std::ratio; using r2 = std::ratio; diff --git a/test/metabench/make_dimension/dimension_concepts_iface.h b/test/metabench/make_dimension/dimension_concepts_iface.h index ca104c0d..069c7458 100644 --- a/test/metabench/make_dimension/dimension_concepts_iface.h +++ b/test/metabench/make_dimension/dimension_concepts_iface.h @@ -62,7 +62,7 @@ namespace units { // exp - template + template struct exp { static constexpr const base_dimension& dimension = BaseDimension; static constexpr int num = Num; @@ -74,7 +74,7 @@ namespace units { template inline constexpr bool is_exp = false; - template + template inline constexpr bool is_exp> = true; } // namespace detail @@ -92,7 +92,7 @@ namespace units { template struct exp_invert; - template + template struct exp_invert> { using type = exp; }; @@ -160,7 +160,7 @@ namespace units { using type = conditional>, dimension, type_list_push_front>; }; - template + template struct dim_consolidate, exp, ERest...>> { using r1 = std::ratio; using r2 = std::ratio; diff --git a/test/metabench/make_dimension/dimension_no_concepts.h b/test/metabench/make_dimension/dimension_no_concepts.h index ac8f8688..569a4ba1 100644 --- a/test/metabench/make_dimension/dimension_no_concepts.h +++ b/test/metabench/make_dimension/dimension_no_concepts.h @@ -62,11 +62,11 @@ namespace units { // exp - template + template struct exp { static constexpr const base_dimension& dimension = BaseDimension; - static constexpr int num = Num; - static constexpr int den = Den; + static constexpr std::intmax_t num = Num; + static constexpr std::intmax_t den = Den; }; // exp_dim_id_less @@ -80,7 +80,7 @@ namespace units { template struct exp_invert; - template + template struct exp_invert> { using type = exp; }; @@ -131,7 +131,7 @@ namespace units { using type = conditional>, dimension, type_list_push_front>; }; - template + template struct dim_consolidate, exp, ERest...>> { using r1 = std::ratio; using r2 = std::ratio; diff --git a/test/unit_test/runtime/CMakeLists.txt b/test/unit_test/runtime/CMakeLists.txt index 2100a485..27ab610a 100644 --- a/test/unit_test/runtime/CMakeLists.txt +++ b/test/unit_test/runtime/CMakeLists.txt @@ -20,6 +20,9 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +# check if conan installed a test framework +conan_check_testing(Catch2) + add_executable(unit_tests_runtime catch_main.cpp digital_info_test.cpp