#pragma once
#include <algorithm>
#include <cstdint>
#include <folly/Bits.h>
#include <folly/ConstexprMath.h>
#include <folly/Likely.h>
#include <folly/Portability.h>
#include <folly/container/detail/F14IntrinsicsAvailability.h>
#include <folly/lang/Assume.h>
#include <folly/lang/SafeAssert.h>
#if FOLLY_F14_VECTOR_INTRINSICS_AVAILABLE
namespace folly {
namespace f14 {
namespace detail {
template <typename T>
FOLLY_ALWAYS_INLINE static unsigned findFirstSetNonZero(T mask) { … }
#if FOLLY_NEON
MaskType;
constexpr unsigned kMaskSpacing = …;
#else
using MaskType = uint32_t;
constexpr unsigned kMaskSpacing = 1;
#endif
template <unsigned BitCount>
struct FullMask { … };
template <>
struct FullMask<1> : std::integral_constant<MaskType, 1> { … };
#if FOLLY_ARM
class SparseMaskIter {
static_assert(kMaskSpacing == 4, "");
uint32_t interleavedMask_;
public:
explicit SparseMaskIter(MaskType mask)
: interleavedMask_{static_cast<uint32_t>(((mask >> 32) << 2) | mask)} {}
bool hasNext() { return interleavedMask_ != 0; }
unsigned next() {
FOLLY_SAFE_DCHECK(hasNext(), "");
unsigned i = findFirstSetNonZero(interleavedMask_);
interleavedMask_ &= (interleavedMask_ - 1);
return ((i >> 2) | (i << 2)) & 0xf;
}
};
class DenseMaskIter {
static_assert(kMaskSpacing == 4, "");
std::size_t count_;
unsigned index_;
uint8_t const* tags_;
public:
explicit DenseMaskIter(uint8_t const* tags, MaskType mask) {
if (mask == 0) {
count_ = 0;
} else {
count_ = popcount(static_cast<uint32_t>(((mask >> 32) << 2) | mask));
if (FOLLY_LIKELY((mask & 1) != 0)) {
index_ = 0;
} else {
index_ = findFirstSetNonZero(mask) / kMaskSpacing;
}
tags_ = tags;
}
}
bool hasNext() { return count_ > 0; }
unsigned next() {
auto rv = index_;
--count_;
if (count_ > 0) {
do {
++index_;
} while ((tags_[index_] & 0x80) == 0);
}
FOLLY_SAFE_DCHECK(index_ < 16, "");
return rv;
}
};
#else
class SparseMaskIter { … };
class DenseMaskIter { … };
#endif
class MaskRangeIter { … };
class LastOccupiedInMask { … };
class FirstEmptyInMask { … };
}
}
}
#endif