#ifndef COMPONENTS_AUTOFILL_CORE_COMMON_DENSE_SET_H_
#define COMPONENTS_AUTOFILL_CORE_COMMON_DENSE_SET_H_
#include <array>
#include <bit>
#include <climits>
#include <cstddef>
#include <iterator>
#include <type_traits>
#include "base/check.h"
#include "base/check_op.h"
#include "base/containers/span.h"
#include "base/memory/raw_ptr.h"
#include "base/numerics/safe_conversions.h"
namespace autofill {
namespace internal {
kBitsPer;
template <typename Word, size_t kNumWords>
class Bitset { … };
Bitset<Word, 1U>;
}
template <typename T>
struct DenseSetTraits { … };
template <typename T, typename Traits = DenseSetTraits<T>>
class DenseSet {
private:
static_assert(std::is_integral<T>::value || std::is_enum<T>::value);
struct Wrapper {
using type = T;
};
using UnderlyingType = typename std::conditional_t<std::is_enum<T>::value,
std::underlying_type<T>,
Wrapper>::type;
using Index = std::make_unsigned_t<UnderlyingType>;
static constexpr UnderlyingType to_underlying(T x) { … }
static_assert(to_underlying(Traits::kMinValue) <=
to_underlying(Traits::kMaxValue));
static constexpr size_t kMaxBitIndex = base::checked_cast<Index>(
to_underlying(Traits::kMaxValue) - to_underlying(Traits::kMinValue));
static_assert(kMaxBitIndex <
std::numeric_limits<decltype(kMaxBitIndex)>::max());
public:
using Word = std::conditional_t<
(Traits::kPacked || kMaxBitIndex < 8),
uint8_t,
std::conditional_t<
(kMaxBitIndex < 16),
uint16_t,
std::conditional_t<(kMaxBitIndex < 32), uint32_t, uint64_t>>>;
private:
static constexpr size_t ceil_div(size_t x, size_t y) { … }
public:
static constexpr size_t kNumWords =
ceil_div(kMaxBitIndex + 1, internal::kBitsPer<Word>);
class Iterator {
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = T;
using difference_type = std::ptrdiff_t;
using pointer = void;
using reference = T;
constexpr Iterator() = default;
friend bool operator==(const Iterator& a, const Iterator& b) {
DCHECK(a.owner_);
DCHECK_EQ(a.owner_, b.owner_);
return a.index_ == b.index_;
}
friend bool operator!=(const Iterator& a, const Iterator& b) {
return !(a == b);
}
T operator*() const {
DCHECK(dereferenceable());
return index_to_value(index_);
}
Iterator& operator++() {
++index_;
Skip(kForward);
return *this;
}
Iterator operator++(int) {
auto that = *this;
operator++();
return that;
}
Iterator& operator--() {
--index_;
Skip(kBackward);
return *this;
}
Iterator operator--(int) {
auto that = *this;
operator--();
return that;
}
private:
friend DenseSet;
enum Direction { kBackward = -1, kForward = 1 };
constexpr Iterator(const DenseSet* owner, Index index)
: owner_(owner), index_(index) {}
void Skip(Direction direction) {
DCHECK_LE(index_, owner_->max_size());
while (index_ < owner_->max_size() && !dereferenceable()) {
index_ += direction;
}
}
bool dereferenceable() const {
DCHECK_LT(index_, owner_->max_size());
return owner_->bitset_.get_bit(index_);
}
raw_ptr<const DenseSet<T, Traits>> owner_ = nullptr;
Index index_ = 0;
};
using value_type = T;
using iterator = Iterator;
using const_iterator = Iterator;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
constexpr DenseSet() = default;
constexpr DenseSet(std::initializer_list<T> init) { … }
template <typename InputIt>
DenseSet(InputIt first, InputIt last) { … }
static constexpr DenseSet all() { … }
constexpr base::span<const Word, kNumWords> data() const { … }
friend auto operator<=>(const DenseSet& a, const DenseSet& b) = default;
friend bool operator==(const DenseSet& a, const DenseSet& b) = default;
iterator begin() const { … }
const_iterator cbegin() const { … }
iterator end() const { … }
const_iterator cend() const { … }
reverse_iterator rbegin() const { … }
const_reverse_iterator crbegin() const { … }
reverse_iterator rend() const { … }
const_reverse_iterator crend() const { … }
constexpr bool empty() const { … }
constexpr size_t size() const { … }
constexpr size_t max_size() const { … }
constexpr void clear() { … }
constexpr std::pair<iterator, bool> insert(T x) { … }
constexpr void insert_all(const DenseSet& xs) { … }
constexpr void intersect(const DenseSet& xs) { … }
size_t erase(T x) { … }
iterator erase(const_iterator it) { … }
iterator erase(const_iterator first, const_iterator last) { … }
void erase_all(const DenseSet& xs) { … }
constexpr size_t count(T x) const { … }
constexpr const_iterator find(T x) const { … }
constexpr bool contains(T x) const { … }
bool contains_none(const DenseSet& xs) const { … }
bool contains_any(const DenseSet& xs) const { … }
bool contains_all(const DenseSet& xs) const { … }
const_iterator lower_bound(T x) const { … }
const_iterator upper_bound(T x) const { … }
private:
friend Iterator;
using Bitset = internal::Bitset<Word, kNumWords>;
static constexpr Index value_to_index(T x) { … }
static constexpr T index_to_value(Index i) { … }
Bitset bitset_{};
};
template <typename T, typename... Ts>
requires(std::same_as<T, Ts> && ...)
DenseSet(T, Ts...) -> DenseSet<T>;
template <typename InputIt>
DenseSet(InputIt first, InputIt last)
-> DenseSet<typename std::iterator_traits<InputIt>::value_type>;
}
#endif