Skip to content

Commit

Permalink
make bit_set fully constexpr
Browse files Browse the repository at this point in the history
  • Loading branch information
rhalbersma committed May 3, 2020
1 parent f8b4651 commit 7866a81
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 51 deletions.
69 changes: 30 additions & 39 deletions include/xstd/bit_set.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::unsigned_integral T>
Expand Down Expand Up @@ -325,7 +313,7 @@ class bit_set
bit_set(ilist.begin(), ilist.end())
{}

XSTD_PP_CONSTEXPR_ALGORITHM auto& operator=(std::initializer_list<value_type> ilist) // Throws: Nothing.
constexpr auto& operator=(std::initializer_list<value_type> ilist) // Throws: Nothing.
{
clear();
insert(ilist.begin(), ilist.end());
Expand Down Expand Up @@ -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) {
Expand All @@ -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) {
Expand Down Expand Up @@ -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;
Expand All @@ -435,7 +423,7 @@ class bit_set
}
}

XSTD_PP_CONSTEXPR_ALGORITHM auto size() const noexcept
constexpr auto size() const noexcept
{
return static_cast<size_type>(ssize());
}
Expand Down Expand Up @@ -487,19 +475,19 @@ class bit_set
}

template<class InputIterator>
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<value_type> ilist) // Throws: Nothing.
constexpr auto insert(std::initializer_list<value_type> 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) {
Expand Down Expand Up @@ -545,15 +533,15 @@ 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);
});
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]);
Expand All @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand All @@ -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) {
Expand All @@ -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) {
Expand All @@ -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) {
Expand Down Expand Up @@ -1203,45 +1194,45 @@ constexpr auto operator-(bit_set<N, Block> const& lhs, bit_set<N, Block> const&
}

template<std::size_t N, std::unsigned_integral Block>
XSTD_PP_CONSTEXPR_ALGORITHM auto operator<<(bit_set<N, Block> const& lhs, int n) // Throws: Nothing.
constexpr auto operator<<(bit_set<N, Block> const& lhs, int n) // Throws: Nothing.
{
assert(0 <= n && n < static_cast<int>(N));
auto nrv{lhs}; nrv <<= n; return nrv;
}

template<std::size_t N, std::unsigned_integral Block>
XSTD_PP_CONSTEXPR_ALGORITHM auto operator>>(bit_set<N, Block> const& lhs, int n) // Throws: Nothing.
constexpr auto operator>>(bit_set<N, Block> const& lhs, int n) // Throws: Nothing.
{
assert(0 <= n && n < static_cast<int>(N));
auto nrv{lhs}; nrv >>= n; return nrv;
}

template<std::size_t N, std::unsigned_integral Block>
XSTD_PP_CONSTEXPR_ALGORITHM auto is_superset_of(bit_set<N, Block> const& lhs, bit_set<N, Block> const& rhs) noexcept
constexpr auto is_superset_of(bit_set<N, Block> const& lhs, bit_set<N, Block> const& rhs) noexcept
{
return is_subset_of(rhs, lhs);
}

template<std::size_t N, std::unsigned_integral Block>
XSTD_PP_CONSTEXPR_ALGORITHM auto is_proper_subset_of(bit_set<N, Block> const& lhs, bit_set<N, Block> const& rhs) noexcept
constexpr auto is_proper_subset_of(bit_set<N, Block> const& lhs, bit_set<N, Block> const& rhs) noexcept
{
return is_subset_of(lhs, rhs) && !is_subset_of(rhs, lhs);
}

template<std::size_t N, std::unsigned_integral Block>
XSTD_PP_CONSTEXPR_ALGORITHM auto is_proper_superset_of(bit_set<N, Block> const& lhs, bit_set<N, Block> const& rhs) noexcept
constexpr auto is_proper_superset_of(bit_set<N, Block> const& lhs, bit_set<N, Block> const& rhs) noexcept
{
return is_superset_of(lhs, rhs) && !is_superset_of(rhs, lhs);
}

template<std::size_t N, std::unsigned_integral Block>
XSTD_PP_CONSTEXPR_ALGORITHM auto disjoint(bit_set<N, Block> const& lhs, bit_set<N, Block> const& rhs) noexcept
constexpr auto disjoint(bit_set<N, Block> const& lhs, bit_set<N, Block> const& rhs) noexcept
{
return !intersects(lhs, rhs);
}

template<std::size_t N, std::unsigned_integral Block>
XSTD_PP_CONSTEXPR_SWAP auto swap(bit_set<N, Block>& lhs, bit_set<N, Block>& rhs) noexcept
constexpr auto swap(bit_set<N, Block>& lhs, bit_set<N, Block>& rhs) noexcept
{
lhs.swap(rhs);
}
Expand Down Expand Up @@ -1319,20 +1310,20 @@ constexpr auto crend(bit_set<N, Block> const& bs) noexcept
}

template<std::size_t N, std::unsigned_integral Block>
XSTD_PP_CONSTEXPR_ALGORITHM auto size(bit_set<N, Block> const& bs) noexcept
constexpr auto size(bit_set<N, Block> const& bs) noexcept
{
return bs.size();
}

template<std::size_t N, std::unsigned_integral Block>
XSTD_PP_CONSTEXPR_ALGORITHM auto ssize(bit_set<N, Block> const& bs) noexcept
constexpr auto ssize(bit_set<N, Block> const& bs) noexcept
{
using R = std::common_type_t<std::ptrdiff_t, std::make_signed_t<decltype(bs.size())>>;
return static_cast<R>(bs.size());
}

template<std::size_t N, std::unsigned_integral Block>
[[nodiscard]] XSTD_PP_CONSTEXPR_ALGORITHM auto empty(bit_set<N, Block> const& bs) noexcept
[[nodiscard]] constexpr auto empty(bit_set<N, Block> const& bs) noexcept
{
return bs.empty();
}
Expand Down
24 changes: 12 additions & 12 deletions test/src/builtin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -28,7 +28,7 @@ using namespace xstd::builtin;
template<class T> inline constexpr auto zero = static_cast<T>( 0);
template<class T> inline constexpr auto ones = static_cast<T>(-1);

BOOST_AUTO_TEST_CASE_TEMPLATE(CountTrailingZerosNonZero, T, unsigned_integer_types)
BOOST_AUTO_TEST_CASE_TEMPLATE(CountTrailingZerosNonZero, T, unsigned_integral)
{
static_assert(ctznz(ones<T>) == 0);
BOOST_CHECK_EQUAL(ctznz(ones<T>), 0);
Expand All @@ -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<T>) == 0);
BOOST_CHECK_EQUAL(clznz(ones<T>), 0);
Expand All @@ -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<T>) == 0);
BOOST_CHECK_EQUAL(popcount(zero<T>), 0);
Expand All @@ -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<T>) == 0);
BOOST_CHECK_EQUAL(bsfnz(ones<T>), 0);
Expand All @@ -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<T>) == std::numeric_limits<T>::digits - 1);
BOOST_CHECK_EQUAL(bsrnz(ones<T>), std::numeric_limits<T>::digits - 1);
Expand All @@ -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<T>) == std::numeric_limits<T>::digits);
BOOST_CHECK_EQUAL(ctz(zero<T>), std::numeric_limits<T>::digits);
Expand All @@ -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<T>) == std::numeric_limits<T>::digits);
BOOST_CHECK_EQUAL(clz(zero<T>), std::numeric_limits<T>::digits);
Expand All @@ -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<T>) == std::numeric_limits<T>::digits);
BOOST_CHECK_EQUAL(bsf(zero<T>), std::numeric_limits<T>::digits);
Expand All @@ -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<T>) == -1);
BOOST_CHECK_EQUAL(bsr(zero<T>), -1);
Expand All @@ -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<T>::digits; ++i) {
auto const b = bit1<T>(i);
Expand All @@ -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<T>);
Expand Down
Loading

0 comments on commit 7866a81

Please sign in to comment.