From 7866a81bf6cee7586a65b8506175d23a40de62c2 Mon Sep 17 00:00:00 2001 From: rhalbersma Date: Sun, 3 May 2020 13:27:39 +0200 Subject: [PATCH] make bit_set fully constexpr --- include/xstd/bit_set.hpp | 69 ++++++++++++++----------------- test/src/builtin.cpp | 24 +++++------ test/src/set/constexpr.cpp | 85 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+), 51 deletions(-) create mode 100644 test/src/set/constexpr.cpp diff --git a/include/xstd/bit_set.hpp b/include/xstd/bit_set.hpp index 23ec0fc..4c463d8 100644 --- a/include/xstd/bit_set.hpp +++ b/include/xstd/bit_set.hpp @@ -56,18 +56,6 @@ namespace xstd { #endif -#if defined(__GNUG__) - -#define XSTD_PP_CONSTEXPR_ALGORITHM constexpr // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0202r3.html -#define XSTD_PP_CONSTEXPR_SWAP constexpr // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0879r0.html - -#elif defined(_MSC_VER) - -#define XSTD_PP_CONSTEXPR_ALGORITHM /* constexpr */ -#define XSTD_PP_CONSTEXPR_SWAP /* constexpr */ - -#endif - namespace builtin { template @@ -325,7 +313,7 @@ class bit_set bit_set(ilist.begin(), ilist.end()) {} - XSTD_PP_CONSTEXPR_ALGORITHM auto& operator=(std::initializer_list ilist) // Throws: Nothing. + constexpr auto& operator=(std::initializer_list ilist) // Throws: Nothing. { clear(); insert(ilist.begin(), ilist.end()); @@ -361,7 +349,7 @@ class bit_set return { *this, find_back() }; } - [[nodiscard]] XSTD_PP_CONSTEXPR_ALGORITHM auto empty() const noexcept + [[nodiscard]] constexpr auto empty() const noexcept -> bool { if constexpr (num_logical_blocks == 0) { @@ -380,7 +368,7 @@ class bit_set } } - [[nodiscard]] XSTD_PP_CONSTEXPR_ALGORITHM auto full() const noexcept + [[nodiscard]] constexpr auto full() const noexcept { if constexpr (num_excess_bits == 0) { if constexpr (num_logical_blocks == 0) { @@ -417,7 +405,7 @@ class bit_set } } - XSTD_PP_CONSTEXPR_ALGORITHM auto ssize() const noexcept + constexpr auto ssize() const noexcept { if constexpr (num_logical_blocks == 0) { return 0; @@ -435,7 +423,7 @@ class bit_set } } - XSTD_PP_CONSTEXPR_ALGORITHM auto size() const noexcept + constexpr auto size() const noexcept { return static_cast(ssize()); } @@ -487,19 +475,19 @@ class bit_set } template - XSTD_PP_CONSTEXPR_ALGORITHM auto insert(InputIterator first, InputIterator last) // Throws: Nothing. + constexpr auto insert(InputIterator first, InputIterator last) // Throws: Nothing. { std::for_each(first, last, [&](auto const& x) { insert(x); }); } - XSTD_PP_CONSTEXPR_ALGORITHM auto insert(std::initializer_list ilist) // Throws: Nothing. + constexpr auto insert(std::initializer_list ilist) // Throws: Nothing. { insert(ilist.begin(), ilist.end()); } - XSTD_PP_CONSTEXPR_ALGORITHM auto& fill() noexcept + constexpr auto& fill() noexcept { if constexpr (num_excess_bits == 0) { if constexpr (num_logical_blocks == 1) { @@ -545,7 +533,7 @@ class bit_set return pos; } - XSTD_PP_CONSTEXPR_ALGORITHM auto erase(const_iterator first, const_iterator last) // Throws: Nothing. + constexpr auto erase(const_iterator first, const_iterator last) // Throws: Nothing. { std::for_each(first, last, [&](auto const& x) { erase(x); @@ -553,7 +541,7 @@ class bit_set return last; } - XSTD_PP_CONSTEXPR_SWAP auto swap(bit_set& other [[maybe_unused]]) noexcept + constexpr auto swap(bit_set& other [[maybe_unused]]) noexcept { if constexpr (num_logical_blocks == 1) { std::swap(m_data[0], other.m_data[0]); @@ -565,7 +553,7 @@ class bit_set } } - XSTD_PP_CONSTEXPR_ALGORITHM auto& clear() noexcept + constexpr auto& clear() noexcept { if constexpr (num_logical_blocks == 1) { m_data[0] = zero; @@ -744,7 +732,7 @@ class bit_set return *this; } - XSTD_PP_CONSTEXPR_ALGORITHM auto& operator<<=(value_type n [[maybe_unused]]) // Throws: Nothing. + constexpr auto& operator<<=(value_type n [[maybe_unused]]) // Throws: Nothing. { assert(is_valid(n)); if constexpr (num_logical_blocks == 1) { @@ -778,7 +766,7 @@ class bit_set return *this; } - XSTD_PP_CONSTEXPR_ALGORITHM auto& operator>>=(value_type n [[maybe_unused]]) // Throws: Nothing. + constexpr auto& operator>>=(value_type n [[maybe_unused]]) // Throws: Nothing. { assert(is_valid(n)); if constexpr (num_logical_blocks == 1) { @@ -811,7 +799,10 @@ class bit_set return *this; } - XSTD_PP_CONSTEXPR_ALGORITHM auto operator==(bit_set const& other [[maybe_unused]]) const noexcept + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94924 + // constexpr bool operator==(bit_set const&) const noexcept = default; + + constexpr auto operator==(bit_set const& other [[maybe_unused]]) const noexcept -> bool { if constexpr (num_logical_blocks == 0) { @@ -829,7 +820,7 @@ class bit_set } } - XSTD_PP_CONSTEXPR_ALGORITHM auto operator<=>(bit_set const& other [[maybe_unused]]) const noexcept + constexpr auto operator<=>(bit_set const& other [[maybe_unused]]) const noexcept -> std::strong_ordering { if constexpr (num_logical_blocks == 0) { @@ -847,7 +838,7 @@ class bit_set } } - friend XSTD_PP_CONSTEXPR_ALGORITHM auto is_subset_of(bit_set const& lhs [[maybe_unused]], bit_set const& rhs [[maybe_unused]]) noexcept + friend constexpr auto is_subset_of(bit_set const& lhs [[maybe_unused]], bit_set const& rhs [[maybe_unused]]) noexcept -> bool { if constexpr (num_logical_blocks == 0) { @@ -868,7 +859,7 @@ class bit_set } } - friend XSTD_PP_CONSTEXPR_ALGORITHM auto intersects(bit_set const& lhs [[maybe_unused]], bit_set const& rhs [[maybe_unused]]) noexcept + friend constexpr auto intersects(bit_set const& lhs [[maybe_unused]], bit_set const& rhs [[maybe_unused]]) noexcept -> bool { if constexpr (num_logical_blocks == 0) { @@ -1203,45 +1194,45 @@ constexpr auto operator-(bit_set const& lhs, bit_set const& } template -XSTD_PP_CONSTEXPR_ALGORITHM auto operator<<(bit_set const& lhs, int n) // Throws: Nothing. +constexpr auto operator<<(bit_set const& lhs, int n) // Throws: Nothing. { assert(0 <= n && n < static_cast(N)); auto nrv{lhs}; nrv <<= n; return nrv; } template -XSTD_PP_CONSTEXPR_ALGORITHM auto operator>>(bit_set const& lhs, int n) // Throws: Nothing. +constexpr auto operator>>(bit_set const& lhs, int n) // Throws: Nothing. { assert(0 <= n && n < static_cast(N)); auto nrv{lhs}; nrv >>= n; return nrv; } template -XSTD_PP_CONSTEXPR_ALGORITHM auto is_superset_of(bit_set const& lhs, bit_set const& rhs) noexcept +constexpr auto is_superset_of(bit_set const& lhs, bit_set const& rhs) noexcept { return is_subset_of(rhs, lhs); } template -XSTD_PP_CONSTEXPR_ALGORITHM auto is_proper_subset_of(bit_set const& lhs, bit_set const& rhs) noexcept +constexpr auto is_proper_subset_of(bit_set const& lhs, bit_set const& rhs) noexcept { return is_subset_of(lhs, rhs) && !is_subset_of(rhs, lhs); } template -XSTD_PP_CONSTEXPR_ALGORITHM auto is_proper_superset_of(bit_set const& lhs, bit_set const& rhs) noexcept +constexpr auto is_proper_superset_of(bit_set const& lhs, bit_set const& rhs) noexcept { return is_superset_of(lhs, rhs) && !is_superset_of(rhs, lhs); } template -XSTD_PP_CONSTEXPR_ALGORITHM auto disjoint(bit_set const& lhs, bit_set const& rhs) noexcept +constexpr auto disjoint(bit_set const& lhs, bit_set const& rhs) noexcept { return !intersects(lhs, rhs); } template -XSTD_PP_CONSTEXPR_SWAP auto swap(bit_set& lhs, bit_set& rhs) noexcept +constexpr auto swap(bit_set& lhs, bit_set& rhs) noexcept { lhs.swap(rhs); } @@ -1319,20 +1310,20 @@ constexpr auto crend(bit_set const& bs) noexcept } template -XSTD_PP_CONSTEXPR_ALGORITHM auto size(bit_set const& bs) noexcept +constexpr auto size(bit_set const& bs) noexcept { return bs.size(); } template -XSTD_PP_CONSTEXPR_ALGORITHM auto ssize(bit_set const& bs) noexcept +constexpr auto ssize(bit_set const& bs) noexcept { using R = std::common_type_t>; return static_cast(bs.size()); } template -[[nodiscard]] XSTD_PP_CONSTEXPR_ALGORITHM auto empty(bit_set const& bs) noexcept +[[nodiscard]] constexpr auto empty(bit_set const& bs) noexcept { return bs.empty(); } diff --git a/test/src/builtin.cpp b/test/src/builtin.cpp index 873d98e..8e68445 100644 --- a/test/src/builtin.cpp +++ b/test/src/builtin.cpp @@ -11,7 +11,7 @@ BOOST_AUTO_TEST_SUITE(Builtin) -using unsigned_integer_types = boost::mpl::vector +using unsigned_integral = boost::mpl::vector < uint8_t , uint16_t , uint32_t @@ -28,7 +28,7 @@ using namespace xstd::builtin; template inline constexpr auto zero = static_cast( 0); template inline constexpr auto ones = static_cast(-1); -BOOST_AUTO_TEST_CASE_TEMPLATE(CountTrailingZerosNonZero, T, unsigned_integer_types) +BOOST_AUTO_TEST_CASE_TEMPLATE(CountTrailingZerosNonZero, T, unsigned_integral) { static_assert(ctznz(ones) == 0); BOOST_CHECK_EQUAL(ctznz(ones), 0); @@ -39,7 +39,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(CountTrailingZerosNonZero, T, unsigned_integer_typ } } -BOOST_AUTO_TEST_CASE_TEMPLATE(CountLeadingZerosNonZero, T, unsigned_integer_types) +BOOST_AUTO_TEST_CASE_TEMPLATE(CountLeadingZerosNonZero, T, unsigned_integral) { static_assert(clznz(ones) == 0); BOOST_CHECK_EQUAL(clznz(ones), 0); @@ -50,7 +50,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(CountLeadingZerosNonZero, T, unsigned_integer_type } } -BOOST_AUTO_TEST_CASE_TEMPLATE(Popcount, T, unsigned_integer_types) +BOOST_AUTO_TEST_CASE_TEMPLATE(Popcount, T, unsigned_integral) { static_assert(popcount(zero) == 0); BOOST_CHECK_EQUAL(popcount(zero), 0); @@ -64,7 +64,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(Popcount, T, unsigned_integer_types) } } -BOOST_AUTO_TEST_CASE_TEMPLATE(BitScanForwardNonZero, T, unsigned_integer_types) +BOOST_AUTO_TEST_CASE_TEMPLATE(BitScanForwardNonZero, T, unsigned_integral) { static_assert(bsfnz(ones) == 0); BOOST_CHECK_EQUAL(bsfnz(ones), 0); @@ -75,7 +75,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(BitScanForwardNonZero, T, unsigned_integer_types) } } -BOOST_AUTO_TEST_CASE_TEMPLATE(BitScanReverseNonZero, T, unsigned_integer_types) +BOOST_AUTO_TEST_CASE_TEMPLATE(BitScanReverseNonZero, T, unsigned_integral) { static_assert(bsrnz(ones) == std::numeric_limits::digits - 1); BOOST_CHECK_EQUAL(bsrnz(ones), std::numeric_limits::digits - 1); @@ -86,7 +86,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(BitScanReverseNonZero, T, unsigned_integer_types) } } -BOOST_AUTO_TEST_CASE_TEMPLATE(CountTrailingZeros, T, unsigned_integer_types) +BOOST_AUTO_TEST_CASE_TEMPLATE(CountTrailingZeros, T, unsigned_integral) { static_assert(ctz(zero) == std::numeric_limits::digits); BOOST_CHECK_EQUAL(ctz(zero), std::numeric_limits::digits); @@ -100,7 +100,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(CountTrailingZeros, T, unsigned_integer_types) } } -BOOST_AUTO_TEST_CASE_TEMPLATE(CountLeadingZeros, T, unsigned_integer_types) +BOOST_AUTO_TEST_CASE_TEMPLATE(CountLeadingZeros, T, unsigned_integral) { static_assert(clz(zero) == std::numeric_limits::digits); BOOST_CHECK_EQUAL(clz(zero), std::numeric_limits::digits); @@ -114,7 +114,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(CountLeadingZeros, T, unsigned_integer_types) } } -BOOST_AUTO_TEST_CASE_TEMPLATE(BitScanForward, T, unsigned_integer_types) +BOOST_AUTO_TEST_CASE_TEMPLATE(BitScanForward, T, unsigned_integral) { static_assert(bsf(zero) == std::numeric_limits::digits); BOOST_CHECK_EQUAL(bsf(zero), std::numeric_limits::digits); @@ -128,7 +128,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(BitScanForward, T, unsigned_integer_types) } } -BOOST_AUTO_TEST_CASE_TEMPLATE(BitScanReverse, T, unsigned_integer_types) +BOOST_AUTO_TEST_CASE_TEMPLATE(BitScanReverse, T, unsigned_integral) { static_assert(bsr(zero) == -1); BOOST_CHECK_EQUAL(bsr(zero), -1); @@ -142,7 +142,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(BitScanReverse, T, unsigned_integer_types) } } -BOOST_AUTO_TEST_CASE_TEMPLATE(Bit1, T, unsigned_integer_types) +BOOST_AUTO_TEST_CASE_TEMPLATE(Bit1, T, unsigned_integral) { for (auto i = 0; i < std::numeric_limits::digits; ++i) { auto const b = bit1(i); @@ -153,7 +153,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(Bit1, T, unsigned_integer_types) } } -BOOST_AUTO_TEST_CASE_TEMPLATE(IsNoThrowSwappable, T, unsigned_integer_types) +BOOST_AUTO_TEST_CASE_TEMPLATE(IsNoThrowSwappable, T, unsigned_integral) { // swap() is noexcept if-and-only-if the block_type is no-throw swappable static_assert(std::is_nothrow_swappable_v); diff --git a/test/src/set/constexpr.cpp b/test/src/set/constexpr.cpp new file mode 100644 index 0000000..5f92964 --- /dev/null +++ b/test/src/set/constexpr.cpp @@ -0,0 +1,85 @@ +// Copyright Rein Halbersma 2014-2020. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS +#define BOOST_MPL_LIMIT_VECTOR_SIZE 50 + +#include // bit_set +#include // vector +#include // BOOST_AUTO_TEST_SUITE, BOOST_AUTO_TEST_SUITE_END, BOOST_AUTO_TEST_CASE_TEMPLATE, BOOST_CHECK_EQUAL_COLLECTIONS +#include // strong_ordering + +BOOST_AUTO_TEST_SUITE(Constexpr) + +using namespace xstd; + +using int_set_types = boost::mpl::vector +< bit_set< 0, uint8_t> +, bit_set< 1, uint8_t> +, bit_set< 7, uint8_t> +, bit_set< 8, uint8_t> +, bit_set< 9, uint8_t> +, bit_set< 15, uint8_t> +, bit_set< 16, uint8_t> +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94933 +// , bit_set< 17, uint8_t> +// , bit_set< 24, uint8_t> +, bit_set< 0, uint16_t> +, bit_set< 1, uint16_t> +, bit_set< 15, uint16_t> +, bit_set< 16, uint16_t> +, bit_set< 17, uint16_t> +, bit_set< 31, uint16_t> +, bit_set< 32, uint16_t> +, bit_set< 33, uint16_t> +, bit_set< 48, uint16_t> +, bit_set< 0, uint32_t> +, bit_set< 1, uint32_t> +, bit_set< 31, uint32_t> +, bit_set< 32, uint32_t> +, bit_set< 33, uint32_t> +, bit_set< 63, uint32_t> +, bit_set< 64, uint32_t> +, bit_set< 65, uint32_t> +#if defined(__GNUG__) || defined(_MSC_VER) && defined(WIN64) +, bit_set< 0, uint64_t> +, bit_set< 1, uint64_t> +, bit_set< 63, uint64_t> +, bit_set< 64, uint64_t> +, bit_set< 65, uint64_t> +#endif +#if defined(__GNUG__) +, bit_set< 0, __uint128_t> +, bit_set< 1, __uint128_t> +, bit_set<127, __uint128_t> +, bit_set<128, __uint128_t> +, bit_set<129, __uint128_t> +#endif +>; + +BOOST_AUTO_TEST_CASE_TEMPLATE(Empty, T, int_set_types) +{ + constexpr auto b = T{}; + static_assert(b == T{}.fill().clear()); + static_assert(b.empty()); + static_assert(b.size() == 0); + static_assert(b.begin() == b.end()); + static_assert(b == b); + static_assert((b <=> b) == std::strong_ordering::equal); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(Full, T, int_set_types) +{ + constexpr auto b = ~T{}; + static_assert(b == T{}.fill()); + static_assert(b.full()); + static_assert(b.size() == b.max_size()); + static_assert(b.empty() || b.front() == *b.cbegin()); + static_assert(b.empty() || b.back() == *b.crbegin()); + static_assert(b == b); + static_assert((b <=> b) == std::strong_ordering::equal); +} + +BOOST_AUTO_TEST_SUITE_END()