6#include <absl/container/flat_hash_set.h>
17inline static constexpr size_t SizeOf =
sizeof(std::conditional_t<std::is_pointer_v<T>, uintptr_t, T>);
19template<
class T>
class Pool;
25 constexpr Data() noexcept = default;
35 for (
size_t i = 0, e = d1->
size; res && i != e; ++i) res &= d1->
elems[i] == d2->
elems[i];
41 if (!d)
return H::combine(std::move(h), 0);
42 return H::combine_contiguous(std::move(h), d->elems, d->size);
46 static_assert(
sizeof(Data) ==
sizeof(size_t),
"Data.elems should be 0");
51 constexpr PooledSet(
const Data* data) noexcept
58 constexpr
void clear() noexcept { data_ =
nullptr; }
63 constexpr explicit operator bool() const noexcept {
return data_ !=
nullptr; }
64 constexpr bool empty() const noexcept {
return data_ ==
nullptr; }
65 constexpr size_t size() const noexcept {
return empty() ? 0 : data_->
size; }
67 constexpr const T&
front()
const {
return (*
this)[0]; }
68 constexpr const T*
elems()
const {
return data_ ? data_->
elems :
nullptr; }
73 if (*
this == other)
return true;
74 if (!*
this || !other)
return false;
76 for (
auto ai = this->
begin(), ae = this->
end(), bi = other.
begin(), be = other.
end(); ai != ae && bi != be;) {
77 if (*ai == *bi)
return true;
79 if ((*ai)->gid() < (*bi)->gid())
97 constexpr auto begin() const noexcept {
return elems(); }
100 constexpr auto cend() const noexcept {
return end(); }
101 constexpr auto rbegin() const noexcept {
return std::reverse_iterator(
end()); }
102 constexpr auto rend() const noexcept {
return std::reverse_iterator(
begin()); }
104 constexpr auto crend() const noexcept {
return rend(); }
108 const Data* data_ =
nullptr;
111 friend class Pool<T>;
117template<
class T>
struct std::hash<
mim::PooledSet<T>> {
118 constexpr size_t operator()(
mim::PooledSet<T> set)
const {
return std::hash<uintptr_t>()((uintptr_t)set.data_); }
147 auto [data, state] = allocate(1);
148 data->elems[0] = elem;
149 return unify(data, state);
154 auto size = std::distance(begin, end);
155 if (size == 0)
return {};
157 auto [data, state] = allocate(size);
158 auto db = data->elems, de = data->elems + size;
160 std::copy(begin, end, db);
162 auto di = std::unique(db, de);
163 auto actual_size = std::distance(db, di);
164 data->size = actual_size;
165 return unify(data, state, size - actual_size);
170 if (a == b || !b)
return a;
173 auto size = a.size() + b.
size();
174 auto [data, state] = allocate(size);
176 auto di = data->elems;
177 auto ai = a.begin(), ae = a.end(), bi = b.
begin(), be = b.
end();
179 *di = (*ai)->gid() < (*bi)->gid() ? *ai++ : *bi++;
181 while (ai != ae && bi != be)
182 if ((*ai)->gid() < (*bi)->gid())
183 copy_if_unique_and_inc(di, ai);
185 copy_if_unique_and_inc(di, bi);
188 while (ai != ae) copy_if_unique_and_inc(di, ai);
189 while (bi != be) copy_if_unique_and_inc(di, bi);
191 auto actual_size = std::distance(data->elems, di + 1);
192 data->size = actual_size;
193 return unify(data, state, size - actual_size);
198 if (a == b)
return a;
199 if (!a || !b)
return {};
201 auto size = std::min(a.size(), b.
size());
202 auto [data, state] = allocate(size);
204 auto di = data->elems;
205 for (
auto ai = a.begin(), ae = a.end(), bi = b.
begin(), be = b.
end(); ai != ae && bi != be;)
208 else if ((*ai)->gid() < (*bi)->gid())
213 auto actual_size = std::distance(data->elems, di);
214 data->size = actual_size;
215 return unify(data, state, size - actual_size);
225 if (i == a.end())
return a;
227 auto size = a.size() - 1;
230 auto [data, state] = allocate(size);
231 std::copy(i + 1, a.end(), std::copy(a.begin(), i, data->elems));
232 return unify(data, state);
238 swap(p1.arena_, p2.arena_);
239 swap(p1.pool_, p2.pool_);
243 std::pair<Data*, fe::Arena::State> allocate(
size_t size) {
244 auto bytes =
sizeof(Data) + size *
SizeOf<T>;
245 auto state = arena_.state();
246 auto buff = arena_.allocate(bytes,
alignof(Data));
247 auto data =
new (buff) Data(size);
248 return {data, state};
251 PooledSet<T> unify(Data* data, fe::Arena::State state,
size_t excess = 0) {
252 if (data->size == 0) {
253 arena_.deallocate(state);
257 auto [i, ins] = pool_.emplace(data);
260 return PooledSet<T>(data);
263 arena_.deallocate(state);
264 return PooledSet<T>(*i);
267 void copy_if_unique_and_inc(T*& i,
const T*& ai) {
268 if (*i != *ai) *++i = *ai;
273 absl::flat_hash_set<const Data*, absl::Hash<const Data*>,
typename Data::Equal> pool_;
Maintains PooledSets within a fe::Arena and unifies them in a absl::flat_hash_set.
PooledSet< T > merge(PooledSet< T > a, PooledSet< T > b)
Yields .
PooledSet< T > intersect(PooledSet< T > a, PooledSet< T > b)
Yields .
PooledSet< T > create(I begin, I end)
Create a PooledSet wih all elements in the given range.
friend void swap(Pool &p1, Pool &p2) noexcept
PooledSet< T > create(T elem)
Create a PooledSet wih a single element: .
Pool(const Pool &)=delete
PooledSet< T > erase(PooledSet< T > a, const T &elem)
Yields .
PooledSet< T > insert(PooledSet< T > a, const T &elem)
Yields .
Pool & operator=(const Pool &)=delete
Ordered set maintained in a consecutive buffer and unified in Pool.
constexpr auto cend() const noexcept
constexpr bool operator==(PooledSet< T > other) const noexcept
constexpr bool operator!=(PooledSet< T > other) const noexcept
constexpr auto crbegin() const noexcept
constexpr auto end() const noexcept
constexpr size_t size() const noexcept
constexpr const T & operator[](size_t i) const
constexpr auto crend() const noexcept
constexpr PooledSet() noexcept=default
constexpr bool contains(const T &elem) const
constexpr auto begin() const noexcept
constexpr auto rbegin() const noexcept
friend H AbslHashValue(H h, PooledSet< T > set)
bool has_intersection(PooledSet< T > other)
Is ?
constexpr bool empty() const noexcept
constexpr const T * elems() const
constexpr void clear() noexcept
constexpr auto rend() const noexcept
constexpr auto cbegin() const noexcept
constexpr const T & front() const
I binary_find(I begin, I end, T val, L lt)
static constexpr size_t SizeOf
constexpr bool operator()(const Data *d1, const Data *d2) const
friend constexpr H AbslHashValue(H h, const Data *d)
constexpr Data() noexcept=default