From b18061ab0ee2f54528edb6ac357a831184736c8d Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Sun, 21 Feb 2021 00:40:56 +0100 Subject: [PATCH] build: clang support added --- conanfile.py | 12 ++- src/CMakeLists.txt | 1 + src/include/units/bits/external/hacks.h | 119 +++++++++++++++++++++++- 3 files changed, 124 insertions(+), 8 deletions(-) diff --git a/conanfile.py b/conanfile.py index 38d5582f..87080e65 100644 --- a/conanfile.py +++ b/conanfile.py @@ -86,13 +86,15 @@ class UnitsConan(ConanFile): if compiler == "gcc": if version < "10.0": raise ConanInvalidConfiguration("mp-units requires at least g++-10") + elif compiler == "clang": + if version < "12": + raise ConanInvalidConfiguration("mp-units requires at least clang++-12") elif compiler == "Visual Studio": if version < "16": raise ConanInvalidConfiguration("mp-units requires at least Visual Studio 16.7") else: - raise ConanInvalidConfiguration("mp-units is supported only by gcc and Visual Studio so far") - if compiler.get_safe("cppstd"): - check_min_cppstd(self, "20") + raise ConanInvalidConfiguration("Unsupported compiler") + check_min_cppstd(self, "20") # TODO Uncomment this when environment is supported in the Conan toolchain # def config_options(self): @@ -100,6 +102,10 @@ class UnitsConan(ConanFile): # # build_docs has sense only in a development or CI build # del self.options.build_docs + def requirements(self): + if self.settings.compiler == "clang": + self.requires("range-v3/0.11.0") + def build_requirements(self): if self._run_tests: self.build_requires("catch2/2.13.4") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8416b741..c73d7254 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -51,6 +51,7 @@ target_include_directories(mp-units ) if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + find_package(range-v3) target_link_libraries(mp-units INTERFACE range-v3::range-v3 diff --git a/src/include/units/bits/external/hacks.h b/src/include/units/bits/external/hacks.h index 28f781b9..b5f0a517 100644 --- a/src/include/units/bits/external/hacks.h +++ b/src/include/units/bits/external/hacks.h @@ -22,8 +22,6 @@ #pragma once -#include - #if __clang__ #define COMP_CLANG __clang_major__ #elif __GNUC__ @@ -33,7 +31,18 @@ #define COMP_MSVC _MSC_VER #endif -#if COMP_MSVC +#if COMP_CLANG + +#include +#include +#include + +#endif + +#include +#include + +#if COMP_MSVC || COMP_CLANG #define TYPENAME typename @@ -43,13 +52,113 @@ #endif -#if COMP_GCC namespace std { +#if COMP_GCC + template concept default_constructible = constructible_from; -} // namespace std +#elif COMP_CLANG + +// concepts +using concepts::three_way_comparable; +using concepts::three_way_comparable_with; +// using concepts::common_reference_with; +using concepts::common_with; +using concepts::constructible_from; +using concepts::convertible_to; +// using concepts::default_constructible; +using concepts::derived_from; +// using concepts::equality_comparable; +using concepts::equality_comparable_with; +// // using concepts::floating_point; +// using concepts::integral; +using concepts::regular; +// using concepts::same_as; +// using concepts::totally_ordered; +// using concepts::totally_ordered_with; + +using ranges::compare_three_way; + +// namespace ranges { + +// using ::ranges::forward_range; +// using ::ranges::range_value_t; + +// } + +// // missing in Range-v3 +// template +// concept floating_point = std::is_floating_point_v; + +template +concept invocable = +requires(F&& f, Args&&... args) { + std::invoke(std::forward(f), std::forward(args)...); +}; + +template +concept regular_invocable = invocable; + +template +constexpr bool cmp_equal(T t, U u) noexcept +{ + using UT = std::make_unsigned_t; + using UU = std::make_unsigned_t; + if constexpr (std::is_signed_v == std::is_signed_v) + return t == u; + else if constexpr (std::is_signed_v) + return t < 0 ? false : UT(t) == u; + else + return u < 0 ? false : t == UU(u); +} + +template +constexpr bool cmp_not_equal(T t, U u) noexcept +{ + return !cmp_equal(t, u); +} + +template +constexpr bool cmp_less(T t, U u) noexcept +{ + using UT = std::make_unsigned_t; + using UU = std::make_unsigned_t; + if constexpr (std::is_signed_v == std::is_signed_v) + return t < u; + else if constexpr (std::is_signed_v) + return t < 0 ? true : UT(t) < u; + else + return u < 0 ? false : t < UU(u); +} + +template +constexpr bool cmp_greater(T t, U u) noexcept +{ + return cmp_less(u, t); +} + +template +constexpr bool cmp_less_equal(T t, U u) noexcept +{ + return !cmp_greater(t, u); +} + +template +constexpr bool cmp_greater_equal(T t, U u) noexcept +{ + return !cmp_less(t, u); +} + +template +constexpr bool in_range(T t) noexcept +{ + return std::cmp_greater_equal(t, std::numeric_limits::min()) && + std::cmp_less_equal(t, std::numeric_limits::max()); +} #endif + +} // namespace std