Skip to content

Commit

Permalink
Use concepts instead of SFINAE in bitset_extensions
Browse files Browse the repository at this point in the history
Use concepts to test GCC intrinsics precence, instead of SFINAE
  • Loading branch information
p-senichenkov committed Dec 19, 2024
1 parent aab5523 commit 6cd31a0
Showing 1 changed file with 17 additions and 38 deletions.
55 changes: 17 additions & 38 deletions src/core/util/bitset_extensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,10 @@ static std::vector<unsigned long long> const kBytes{0xff,
constexpr static size_t kNumBytes = 8;
constexpr static size_t kWidth = 64;

// std::vector::operator[] is constexpr only since GCC 12
// (see https://en.cppreference.com/w/cpp/compiler_support)
// FIXME(senichenkov): check old versions of other compilers
#if defined(__GNUC__) && (__GNUC__ < 12)
#define CONSTEXPR_IF_VECTOR_IS_CONSTEXPR /* Ignore */
#if (__cpp_lib_constexpr_vector == 201907L)
#define CONSTEXPR_IF_VECTOR_IS_CONSTEXPR constexpr
#else
#define CONSTEXPR_IF_VECTOR_IS_CONSTEXPR conxtexpr
#define CONSTEXPR_IF_VECTOR_IS_CONSTEXPR /* Ignore */
#endif

CONSTEXPR_IF_VECTOR_IS_CONSTEXPR unsigned char GetByte(unsigned long long val, size_t byte_num);
Expand All @@ -54,26 +51,8 @@ size_t FindFirstFixedWidth(std::bitset<kWidth> const&);

size_t FindNextFixedWidth(std::bitset<kWidth> const&, size_t pos);

/// @brief Test if T has method _Find_next using SFINAE
template <typename T>
struct TestBitset {
private:
typedef char yes[1];
typedef char no[2];

template <typename Tp>
static yes& Test(decltype(&Tp::_Find_next));

template <typename Tp>
static no& Test(...);

public:
static bool const kValue = sizeof(Test<T>(nullptr)) == sizeof(yes);
};

/// @brief Test if T has method _Find_next
template <typename T>
constexpr bool kTestBitsetV = TestBitset<T>::kValue;
template <typename Bitset>
concept HasFindFirst = requires(Bitset bs) { bs._Find_first(); };

/// @brief Wrapper for std::bitset to iterate through set bits using temporary
/// boost::dynamic_bitset.
Expand Down Expand Up @@ -129,27 +108,27 @@ class BitsetIterator : public IBitsetIterator {
} // namespace bitset_extensions

/// @brief Call bs._Find_first if it's availible, use custom implementation otherwise
template <size_t S, typename std::enable_if<bitset_extensions::kTestBitsetV<std::bitset<S>>,
bool>::type = true>
template <size_t S>
requires bitset_extensions::HasFindFirst<std::bitset<S>>
inline size_t FindFirst(std::bitset<S> const& bs) noexcept {
return bs._Find_first();
}

/// @brief Call bs._Find_first if it's availible, use custom implementation otherwise
template <size_t S, typename = std::enable_if_t<!bitset_extensions::kTestBitsetV<std::bitset<S>>>>
template <size_t S>
inline size_t FindFirst(std::bitset<S> const& bs) noexcept {
return bitset_extensions::FindFirstFixedWidth(bs);
}

/// @brief Call bs._Find_next if it's availible, use custom implementation otherwise
template <size_t S, typename std::enable_if<bitset_extensions::kTestBitsetV<std::bitset<S>>,
bool>::type = true>
template <size_t S>
requires bitset_extensions::HasFindFirst<std::bitset<S>>
inline size_t FindNext(std::bitset<S> const& bs, size_t pos) noexcept {
return bs._Find_next(pos);
}

/// @brief Call bs._Find_next if it's availible, use custom implementation otherwise
template <size_t S, typename = std::enable_if_t<!bitset_extensions::kTestBitsetV<std::bitset<S>>>>
template <size_t S>
inline size_t FindNext(std::bitset<S> const& bs, size_t pos) noexcept {
if constexpr (S == 64) {
return bitset_extensions::FindNextFixedWidth(bs, pos);
Expand All @@ -163,8 +142,8 @@ inline size_t FindNext(std::bitset<S> const& bs, size_t pos) noexcept {

/// @brief If _Find_next is availible, copy every set bit, else copy biset to dynamic_bitset
/// through string representation. Bitset is shifted 1 bit left.
template <size_t S, typename std::enable_if<bitset_extensions::kTestBitsetV<std::bitset<S>>,
bool>::type = true>
template <size_t S>
requires bitset_extensions::HasFindFirst<std::bitset<S>>
inline boost::dynamic_bitset<> CreateShiftedDynamicBitset(std::bitset<S> const& bs,
std::size_t size = S) noexcept {
boost::dynamic_bitset<> dyn_bitset(size);
Expand All @@ -176,7 +155,7 @@ inline boost::dynamic_bitset<> CreateShiftedDynamicBitset(std::bitset<S> const&

/// @brief If _Find_next is availible, copy every set bit, else copy biset to dynamic_bitset
/// through string representation. Bitset is shifted 1 bit left.
template <size_t S, typename = std::enable_if_t<!bitset_extensions::kTestBitsetV<std::bitset<S>>>>
template <size_t S>
inline boost::dynamic_bitset<> CreateShiftedDynamicBitset(std::bitset<S> const& bs,
std::size_t size = S) noexcept {
size_t start = S - size - 1;
Expand All @@ -185,15 +164,15 @@ inline boost::dynamic_bitset<> CreateShiftedDynamicBitset(std::bitset<S> const&

/// @brief If _Find_next is availible, create std::bitset set-bits-iterator, else
/// boost::dynamic_bitset set-bits-iterator
template <size_t S, typename std::enable_if<bitset_extensions::kTestBitsetV<std::bitset<S>>,
bool>::type = true>
template <size_t S>
requires bitset_extensions::HasFindFirst<std::bitset<S>>
inline std::unique_ptr<IBitsetIterator> MakeBitsetIterator(std::bitset<S> const& bs) {
return std::make_unique<bitset_extensions::BitsetIterator<S>>(bs);
}

/// @brief If _Find_next is availible, create std::bitset set-bits-iterator, else
/// boost::dynamic_bitset set-bits-iterator
template <size_t S, typename = std::enable_if_t<!bitset_extensions::kTestBitsetV<std::bitset<S>>>>
template <size_t S>
inline std::unique_ptr<IBitsetIterator> MakeBitsetIterator(std::bitset<S> const& bs) {
return std::make_unique<bitset_extensions::DynamicBitsetIterator<S>>(bs);
}
Expand Down

0 comments on commit 6cd31a0

Please sign in to comment.