35namespace DiscordCoreAPI {
37 template<
typename ValueType>
class UnorderedSet;
39 template<
typename SetIterator,
typename ValueType>
40 concept SetContainerIteratorT = std::is_same_v<typename UnorderedSet<ValueType>::iterator, std::decay_t<SetIterator>>;
42 template<
typename ValueType>
43 class UnorderedSet :
protected HashPolicy<UnorderedSet<ValueType>>,
protected jsonifier_internal::alloc_wrapper<ValueType>,
protected ObjectCompare,
protected KeyAccessor {
45 using mapped_type = ValueType;
46 using key_type = mapped_type;
47 using reference = mapped_type&;
48 using value_type = mapped_type;
49 using const_reference =
const mapped_type&;
50 using size_type = uint64_t;
51 using object_compare = ObjectCompare;
52 using key_accessor = KeyAccessor;
53 using hash_policy = HashPolicy<UnorderedSet<mapped_type>>;
54 using key_hasher = hash_policy;
55 using iterator = HashIterator<UnorderedSet<mapped_type>>;
56 using const_iterator = HashIterator<const UnorderedSet<mapped_type>>;
57 using allocator = jsonifier_internal::alloc_wrapper<value_type>;
61 friend const_iterator;
63 inline UnorderedSet(){};
65 inline UnorderedSet& operator=(UnorderedSet&& other)
noexcept {
73 inline UnorderedSet(UnorderedSet&& other)
noexcept {
74 *
this = std::move(other);
77 inline UnorderedSet& operator=(
const UnorderedSet& other) {
81 reserve(other.capacity());
82 for (
const auto& value: other) {
89 inline UnorderedSet(
const UnorderedSet& other) {
93 inline UnorderedSet(std::initializer_list<value_type> list) {
95 for (
auto& value: list) {
96 emplace(std::move(value));
100 template<
typename Args> iterator emplace(Args&& value) {
101 return emplaceInternal(std::forward<Args>(value));
104 template<
typename key_type_new>
inline const_iterator find(key_type_new&& key)
const {
106 auto currentIndex = getKeyAccessor()(key) & (capacityVal - 1);
107 for (size_type x{}; x < static_cast<size_type>(maxLookAheadDistance); ++x, ++currentIndex) {
108 if (sentinelVector[currentIndex] > 0 && object_compare()(getKeyAccessor()(data[currentIndex]), getKeyAccessor()(key))) {
109 return {
this, currentIndex };
116 template<
typename key_type_new>
inline iterator find(key_type_new&& key) {
118 auto currentIndex = getKeyAccessor()(key) & (capacityVal - 1);
119 for (size_type x{}; x < static_cast<size_type>(maxLookAheadDistance); ++x, ++currentIndex) {
120 if (sentinelVector[currentIndex] > 0 && object_compare()(getKeyAccessor()(data[currentIndex]), getKeyAccessor()(key))) {
121 return {
this, currentIndex };
128 template<
typename key_type_new>
inline const_reference operator[](key_type_new&& key)
const {
129 auto iter = find(std::forward<key_type_new>(key));
131 iter = emplace(mapped_type{});
136 template<
typename key_type_new>
inline reference operator[](key_type_new&& key) {
137 auto iter = find(std::forward<key_type_new>(key));
139 iter = emplace(mapped_type{});
144 template<
typename key_type_new>
inline const_reference at(key_type_new&& key)
const {
145 auto iter = find(std::forward<key_type_new>(key));
147 throw DCAException{
"Sorry, but an object by that key doesn't exist in this map." };
152 template<
typename key_type_new>
inline reference at(key_type_new&& key) {
153 auto iter = find(std::forward<key_type_new>(key));
155 throw DCAException{
"Sorry, but an object by that key doesn't exist in this map." };
160 template<
typename key_type_new>
inline bool contains(key_type_new&& key)
const {
162 auto currentIndex = getKeyAccessor()(key) & (capacityVal - 1);
163 for (size_type x{}; x < static_cast<size_type>(maxLookAheadDistance); ++x, ++currentIndex) {
164 if (sentinelVector[currentIndex] > 0 && object_compare()(getKeyAccessor().operator()(data[currentIndex]), getKeyAccessor().operator()(key))) {
172 template<SetContainerIteratorT<mapped_type> SetIterator>
inline iterator erase(SetIterator&& iter) {
174 auto currentIndex =
static_cast<size_type
>(iter.getRawPtr() - data);
175 for (size_type x{}; x < static_cast<size_type>(maxLookAheadDistance); ++x, ++currentIndex) {
176 if (sentinelVector[currentIndex] > 0 && object_compare()(getKeyAccessor()(data[currentIndex]), getKeyAccessor()(iter.operator*()))) {
177 sentinelVector[currentIndex] = 0;
179 return {
this, ++currentIndex };
186 template<
typename key_type_new>
inline iterator erase(key_type_new&& key) {
188 auto currentIndex = getKeyAccessor()(key) & (capacityVal - 1);
189 for (size_type x{}; x < static_cast<size_type>(maxLookAheadDistance); ++x, ++currentIndex) {
190 if (sentinelVector[currentIndex] > 0 && object_compare()(getKeyAccessor()(data[currentIndex]), getKeyAccessor()(key))) {
191 sentinelVector[currentIndex] = 0;
193 return {
this, ++currentIndex };
200 inline const_iterator begin()
const {
201 for (size_type x{ 0 }; x < capacityVal; ++x) {
202 if (sentinelVector[x] > 0) {
209 inline const_iterator end()
const {
213 inline iterator begin() {
214 for (size_type x{ 0 }; x < capacityVal; ++x) {
215 if (sentinelVector[x] > 0) {
222 inline iterator end() {
226 inline bool full()
const {
227 return static_cast<float>(sizeVal) >=
static_cast<float>(capacityVal) * 0.90f;
230 inline size_type size()
const {
234 inline bool empty()
const {
238 inline void reserve(size_type sizeNew) {
242 inline void swap(UnorderedSet& other)
noexcept {
243 std::swap(maxLookAheadDistance, other.maxLookAheadDistance);
244 std::swap(sentinelVector, other.sentinelVector);
245 std::swap(capacityVal, other.capacityVal);
246 std::swap(sizeVal, other.sizeVal);
247 std::swap(data, other.data);
250 inline size_type capacity()
const {
254 inline bool operator==(
const UnorderedSet& other)
const {
255 if (capacityVal != other.capacityVal || sizeVal != other.sizeVal || data != other.data) {
258 for (
auto iter01{ begin() }, iter02{ other.begin() }; iter01 != end(); ++iter01, ++iter02) {
259 if (!object_compare()(iter01.operator*(), iter02.operator*())) {
266 inline void clear() {
267 for (size_type x = 0; x < sentinelVector.size(); ++x) {
268 if (sentinelVector[x] > 0) {
269 getAlloc().destroy(data + x);
270 sentinelVector[x] = 0;
276 inline ~UnorderedSet() {
281 jsonifier::vector<int8_t> sentinelVector{};
282 int8_t maxLookAheadDistance{ minLookups };
283 size_type capacityVal{};
287 template<
typename mapped_type_new>
inline iterator emplaceInternal(mapped_type_new&& value) {
288 if (full() || capacityVal == 0) {
289 resize(capacityVal + 1);
291 auto currentIndex = getKeyAccessor()(value) & (capacityVal - 1);
292 for (size_type x{}; x < static_cast<size_type>(maxLookAheadDistance); ++x, ++currentIndex) {
293 if (sentinelVector[currentIndex] == 0) {
294 new (std::addressof(data[currentIndex])) value_type{ std::forward<mapped_type_new>(value) };
295 sentinelVector[currentIndex] = 1;
297 return {
this, currentIndex };
298 }
else if (sentinelVector[currentIndex] > 0 && object_compare()(getKeyAccessor()(data[currentIndex]), getKeyAccessor()(value))) {
299 if constexpr (!std::is_void_v<mapped_type_new>) {
300 data[currentIndex] = std::forward<mapped_type_new>(value);
302 return {
this, currentIndex };
305 resize(capacityVal + 1);
306 return emplaceInternal(std::forward<mapped_type_new>(value));
309 inline allocator& getAlloc() {
313 inline const hash_policy& getHashPolicy()
const {
317 inline const key_accessor& getKeyAccessor()
const {
321 inline void resize(size_type capacityNew) {
322 auto newSize = getHashPolicy().nextPowerOfTwo(capacityNew);
323 if (newSize > capacityVal) {
324 jsonifier::vector<int8_t> oldSentinelVector = std::move(sentinelVector);
325 auto oldMaxLookAheadDistance = maxLookAheadDistance;
326 auto oldCapacity = capacityVal;
327 auto oldSize = sizeVal;
329 maxLookAheadDistance = getHashPolicy().computeMaxLookAheadDistance(newSize);
331 data = getAlloc().allocate(newSize + 1 + maxLookAheadDistance);
332 sentinelVector.resize(newSize + 1 + maxLookAheadDistance);
333 sentinelVector[newSize + maxLookAheadDistance] = -1;
334 capacityVal = newSize;
335 for (size_type x = 0, y = 0; y < oldSize; ++x) {
336 if (oldSentinelVector[x] > 0) {
338 emplaceInternal(std::move(oldPtr[x]));
341 if (oldPtr && oldCapacity) {
342 getAlloc().deallocate(oldPtr, oldCapacity + 1 + oldMaxLookAheadDistance);
347 inline void reset() {
348 if (data && sizeVal > 0) {
349 for (uint64_t x = 0; x < sentinelVector.size(); ++x) {
350 if (sentinelVector[x] > 0) {
351 getAlloc().destroy(data + x);
354 getAlloc().deallocate(data, capacityVal + 1 + maxLookAheadDistance);
355 sentinelVector.clear();