#ifndef SRC_GN_POINTER_SET_H_
#define SRC_GN_POINTER_SET_H_
#include <functional>
#include <vector>
#include "gn/hash_table_base.h"
struct PointerSetNode {
const void* ptr_;
bool is_null() const { return !ptr_; }
bool is_tombstone() const { return ptr_ == MakeTombstone(); }
bool is_valid() const { return !is_null() && !is_tombstone(); }
size_t hash_value() const { return MakeHash(ptr_); }
static const void* MakeTombstone() {
return reinterpret_cast<const void*>(1u);
}
static size_t MakeHash(const void* ptr) {
return std::hash<const void*>()(ptr);
}
};
template <typename T>
class PointerSet : public HashTableBase<PointerSetNode> {
public:
using NodeType = PointerSetNode;
using BaseType = HashTableBase<NodeType>;
PointerSet() = default;
PointerSet(const PointerSet& other) : BaseType() { insert(other); }
PointerSet& operator=(const PointerSet& other) {
if (this != &other) {
this->~PointerSet();
new (this) PointerSet(other);
}
return *this;
}
PointerSet(PointerSet&& other) noexcept : BaseType(std::move(other)) {}
PointerSet& operator=(PointerSet&& other) noexcept {
if (this != &other) {
this->~PointerSet();
new (this) PointerSet(std::move(other));
}
return *this;
}
template <typename InputIter>
PointerSet(InputIter first, InputIter last) {
for (; first != last; ++first)
add(*first);
}
void clear() { NodeClear(); }
bool add(T* ptr) {
NodeType* node = Lookup(ptr);
if (node->is_valid())
return false;
bool was_tombstone = node->is_tombstone();
node->ptr_ = ptr;
UpdateAfterInsert(was_tombstone);
return true;
}
bool contains(T* ptr) const { return Lookup(ptr)->is_valid(); }
bool erase(T* ptr) {
NodeType* node = Lookup(ptr);
if (!node->is_valid())
return false;
node->ptr_ = node->MakeTombstone();
UpdateAfterRemoval();
return true;
}
void insert(T* ptr) { add(ptr); }
template <typename InputIter>
void insert(InputIter first, InputIter last) {
for (; first != last; ++first)
add(*first);
}
void insert(const PointerSet& other) {
for (const_iterator iter = other.begin(); iter.valid(); ++iter)
add(*iter);
}
PointerSet intersection_with(const PointerSet& other) const {
PointerSet result;
for (const_iterator iter = other.begin(); iter.valid(); ++iter) {
if (contains(*iter))
result.add(*iter);
}
return result;
}
struct const_iterator : public NodeIterator {
T* const* operator->() const {
return &const_cast<T*>(static_cast<const T*>(node_->ptr_));
}
T* operator*() const {
return const_cast<T*>(static_cast<const T*>(node_->ptr_));
}
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = T*;
using pointer = T**;
using reference = T*&;
};
const_iterator begin() const { return {NodeBegin()}; }
const_iterator end() const { return {NodeEnd()}; }
bool operator==(const PointerSet& other) const {
if (size() != other.size())
return false;
for (const_iterator iter = begin(); iter.valid(); ++iter)
if (!other.contains(*iter))
return false;
for (const_iterator iter = other.begin(); iter.valid(); ++iter)
if (!contains(*iter))
return false;
return true;
}
std::vector<T*> ToVector() const {
std::vector<T*> result(this->size());
auto it_result = result.begin();
for (auto it = this->begin(); it.valid(); ++it)
*it_result++ = *it;
return result;
}
private:
NodeType* Lookup(T* ptr) const {
size_t hash = NodeType::MakeHash(ptr);
return NodeLookup(hash, [&](NodeType* node) { return node->ptr_ == ptr; });
}
};
#endif