summaryrefslogtreecommitdiff
path: root/src/common/intrusive_red_black_tree.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/common/intrusive_red_black_tree.h627
1 files changed, 627 insertions, 0 deletions
diff --git a/src/common/intrusive_red_black_tree.h b/src/common/intrusive_red_black_tree.h
new file mode 100644
index 000000000..929b5497e
--- /dev/null
+++ b/src/common/intrusive_red_black_tree.h
@@ -0,0 +1,627 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/parent_of_member.h"
8#include "common/tree.h"
9
10namespace Common {
11
12namespace impl {
13
14class IntrusiveRedBlackTreeImpl;
15
16}
17
18struct IntrusiveRedBlackTreeNode {
19
20private:
21 RB_ENTRY(IntrusiveRedBlackTreeNode) entry{};
22
23 friend class impl::IntrusiveRedBlackTreeImpl;
24
25 template <class, class, class>
26 friend class IntrusiveRedBlackTree;
27
28public:
29 constexpr IntrusiveRedBlackTreeNode() = default;
30};
31
32template <class T, class Traits, class Comparator>
33class IntrusiveRedBlackTree;
34
35namespace impl {
36
37class IntrusiveRedBlackTreeImpl {
38
39private:
40 template <class, class, class>
41 friend class ::Common::IntrusiveRedBlackTree;
42
43private:
44 RB_HEAD(IntrusiveRedBlackTreeRoot, IntrusiveRedBlackTreeNode);
45 using RootType = IntrusiveRedBlackTreeRoot;
46
47private:
48 IntrusiveRedBlackTreeRoot root;
49
50public:
51 template <bool Const>
52 class Iterator;
53
54 using value_type = IntrusiveRedBlackTreeNode;
55 using size_type = size_t;
56 using difference_type = ptrdiff_t;
57 using pointer = value_type*;
58 using const_pointer = const value_type*;
59 using reference = value_type&;
60 using const_reference = const value_type&;
61 using iterator = Iterator<false>;
62 using const_iterator = Iterator<true>;
63
64 template <bool Const>
65 class Iterator {
66 public:
67 using iterator_category = std::bidirectional_iterator_tag;
68 using value_type = typename IntrusiveRedBlackTreeImpl::value_type;
69 using difference_type = typename IntrusiveRedBlackTreeImpl::difference_type;
70 using pointer = std::conditional_t<Const, IntrusiveRedBlackTreeImpl::const_pointer,
71 IntrusiveRedBlackTreeImpl::pointer>;
72 using reference = std::conditional_t<Const, IntrusiveRedBlackTreeImpl::const_reference,
73 IntrusiveRedBlackTreeImpl::reference>;
74
75 private:
76 pointer node;
77
78 public:
79 explicit Iterator(pointer n) : node(n) {}
80
81 bool operator==(const Iterator& rhs) const {
82 return this->node == rhs.node;
83 }
84
85 bool operator!=(const Iterator& rhs) const {
86 return !(*this == rhs);
87 }
88
89 pointer operator->() const {
90 return this->node;
91 }
92
93 reference operator*() const {
94 return *this->node;
95 }
96
97 Iterator& operator++() {
98 this->node = GetNext(this->node);
99 return *this;
100 }
101
102 Iterator& operator--() {
103 this->node = GetPrev(this->node);
104 return *this;
105 }
106
107 Iterator operator++(int) {
108 const Iterator it{*this};
109 ++(*this);
110 return it;
111 }
112
113 Iterator operator--(int) {
114 const Iterator it{*this};
115 --(*this);
116 return it;
117 }
118
119 operator Iterator<true>() const {
120 return Iterator<true>(this->node);
121 }
122 };
123
124protected:
125 // Generate static implementations for non-comparison operations for IntrusiveRedBlackTreeRoot.
126 RB_GENERATE_WITHOUT_COMPARE_STATIC(IntrusiveRedBlackTreeRoot, IntrusiveRedBlackTreeNode, entry);
127
128private:
129 // Define accessors using RB_* functions.
130 constexpr void InitializeImpl() {
131 RB_INIT(&this->root);
132 }
133
134 bool EmptyImpl() const {
135 return RB_EMPTY(&this->root);
136 }
137
138 IntrusiveRedBlackTreeNode* GetMinImpl() const {
139 return RB_MIN(IntrusiveRedBlackTreeRoot,
140 const_cast<IntrusiveRedBlackTreeRoot*>(&this->root));
141 }
142
143 IntrusiveRedBlackTreeNode* GetMaxImpl() const {
144 return RB_MAX(IntrusiveRedBlackTreeRoot,
145 const_cast<IntrusiveRedBlackTreeRoot*>(&this->root));
146 }
147
148 IntrusiveRedBlackTreeNode* RemoveImpl(IntrusiveRedBlackTreeNode* node) {
149 return RB_REMOVE(IntrusiveRedBlackTreeRoot, &this->root, node);
150 }
151
152public:
153 static IntrusiveRedBlackTreeNode* GetNext(IntrusiveRedBlackTreeNode* node) {
154 return RB_NEXT(IntrusiveRedBlackTreeRoot, nullptr, node);
155 }
156
157 static IntrusiveRedBlackTreeNode* GetPrev(IntrusiveRedBlackTreeNode* node) {
158 return RB_PREV(IntrusiveRedBlackTreeRoot, nullptr, node);
159 }
160
161 static IntrusiveRedBlackTreeNode const* GetNext(const IntrusiveRedBlackTreeNode* node) {
162 return static_cast<const IntrusiveRedBlackTreeNode*>(
163 GetNext(const_cast<IntrusiveRedBlackTreeNode*>(node)));
164 }
165
166 static IntrusiveRedBlackTreeNode const* GetPrev(const IntrusiveRedBlackTreeNode* node) {
167 return static_cast<const IntrusiveRedBlackTreeNode*>(
168 GetPrev(const_cast<IntrusiveRedBlackTreeNode*>(node)));
169 }
170
171public:
172 constexpr IntrusiveRedBlackTreeImpl() : root() {
173 this->InitializeImpl();
174 }
175
176 // Iterator accessors.
177 iterator begin() {
178 return iterator(this->GetMinImpl());
179 }
180
181 const_iterator begin() const {
182 return const_iterator(this->GetMinImpl());
183 }
184
185 iterator end() {
186 return iterator(static_cast<IntrusiveRedBlackTreeNode*>(nullptr));
187 }
188
189 const_iterator end() const {
190 return const_iterator(static_cast<const IntrusiveRedBlackTreeNode*>(nullptr));
191 }
192
193 const_iterator cbegin() const {
194 return this->begin();
195 }
196
197 const_iterator cend() const {
198 return this->end();
199 }
200
201 iterator iterator_to(reference ref) {
202 return iterator(&ref);
203 }
204
205 const_iterator iterator_to(const_reference ref) const {
206 return const_iterator(&ref);
207 }
208
209 // Content management.
210 bool empty() const {
211 return this->EmptyImpl();
212 }
213
214 reference back() {
215 return *this->GetMaxImpl();
216 }
217
218 const_reference back() const {
219 return *this->GetMaxImpl();
220 }
221
222 reference front() {
223 return *this->GetMinImpl();
224 }
225
226 const_reference front() const {
227 return *this->GetMinImpl();
228 }
229
230 iterator erase(iterator it) {
231 auto cur = std::addressof(*it);
232 auto next = GetNext(cur);
233 this->RemoveImpl(cur);
234 return iterator(next);
235 }
236};
237
238} // namespace impl
239
240template <typename T>
241concept HasLightCompareType = requires {
242 { std::is_same<typename T::LightCompareType, void>::value }
243 ->std::convertible_to<bool>;
244};
245
246namespace impl {
247
248template <typename T, typename Default>
249consteval auto* GetLightCompareType() {
250 if constexpr (HasLightCompareType<T>) {
251 return static_cast<typename T::LightCompareType*>(nullptr);
252 } else {
253 return static_cast<Default*>(nullptr);
254 }
255}
256
257} // namespace impl
258
259template <typename T, typename Default>
260using LightCompareType = std::remove_pointer_t<decltype(impl::GetLightCompareType<T, Default>())>;
261
262template <class T, class Traits, class Comparator>
263class IntrusiveRedBlackTree {
264
265public:
266 using ImplType = impl::IntrusiveRedBlackTreeImpl;
267
268private:
269 ImplType impl{};
270
271public:
272 struct IntrusiveRedBlackTreeRootWithCompare : ImplType::IntrusiveRedBlackTreeRoot {};
273
274 template <bool Const>
275 class Iterator;
276
277 using value_type = T;
278 using size_type = size_t;
279 using difference_type = ptrdiff_t;
280 using pointer = T*;
281 using const_pointer = const T*;
282 using reference = T&;
283 using const_reference = const T&;
284 using iterator = Iterator<false>;
285 using const_iterator = Iterator<true>;
286
287 using light_value_type = LightCompareType<Comparator, value_type>;
288 using const_light_pointer = const light_value_type*;
289 using const_light_reference = const light_value_type&;
290
291 template <bool Const>
292 class Iterator {
293 public:
294 friend class IntrusiveRedBlackTree<T, Traits, Comparator>;
295
296 using ImplIterator =
297 std::conditional_t<Const, ImplType::const_iterator, ImplType::iterator>;
298
299 using iterator_category = std::bidirectional_iterator_tag;
300 using value_type = typename IntrusiveRedBlackTree::value_type;
301 using difference_type = typename IntrusiveRedBlackTree::difference_type;
302 using pointer = std::conditional_t<Const, IntrusiveRedBlackTree::const_pointer,
303 IntrusiveRedBlackTree::pointer>;
304 using reference = std::conditional_t<Const, IntrusiveRedBlackTree::const_reference,
305 IntrusiveRedBlackTree::reference>;
306
307 private:
308 ImplIterator iterator;
309
310 private:
311 explicit Iterator(ImplIterator it) : iterator(it) {}
312
313 explicit Iterator(typename std::conditional<Const, ImplType::const_iterator,
314 ImplType::iterator>::type::pointer ptr)
315 : iterator(ptr) {}
316
317 ImplIterator GetImplIterator() const {
318 return this->iterator;
319 }
320
321 public:
322 bool operator==(const Iterator& rhs) const {
323 return this->iterator == rhs.iterator;
324 }
325
326 bool operator!=(const Iterator& rhs) const {
327 return !(*this == rhs);
328 }
329
330 pointer operator->() const {
331 return Traits::GetParent(std::addressof(*this->iterator));
332 }
333
334 reference operator*() const {
335 return *Traits::GetParent(std::addressof(*this->iterator));
336 }
337
338 Iterator& operator++() {
339 ++this->iterator;
340 return *this;
341 }
342
343 Iterator& operator--() {
344 --this->iterator;
345 return *this;
346 }
347
348 Iterator operator++(int) {
349 const Iterator it{*this};
350 ++this->iterator;
351 return it;
352 }
353
354 Iterator operator--(int) {
355 const Iterator it{*this};
356 --this->iterator;
357 return it;
358 }
359
360 operator Iterator<true>() const {
361 return Iterator<true>(this->iterator);
362 }
363 };
364
365private:
366 // Generate static implementations for comparison operations for IntrusiveRedBlackTreeRoot.
367 RB_GENERATE_WITH_COMPARE_STATIC(IntrusiveRedBlackTreeRootWithCompare, IntrusiveRedBlackTreeNode,
368 entry, CompareImpl, LightCompareImpl);
369
370private:
371 static int CompareImpl(const IntrusiveRedBlackTreeNode* lhs,
372 const IntrusiveRedBlackTreeNode* rhs) {
373 return Comparator::Compare(*Traits::GetParent(lhs), *Traits::GetParent(rhs));
374 }
375
376 static int LightCompareImpl(const void* elm, const IntrusiveRedBlackTreeNode* rhs) {
377 return Comparator::Compare(*static_cast<const_light_pointer>(elm), *Traits::GetParent(rhs));
378 }
379
380 // Define accessors using RB_* functions.
381 IntrusiveRedBlackTreeNode* InsertImpl(IntrusiveRedBlackTreeNode* node) {
382 return RB_INSERT(IntrusiveRedBlackTreeRootWithCompare,
383 static_cast<IntrusiveRedBlackTreeRootWithCompare*>(&this->impl.root),
384 node);
385 }
386
387 IntrusiveRedBlackTreeNode* FindImpl(const IntrusiveRedBlackTreeNode* node) const {
388 return RB_FIND(
389 IntrusiveRedBlackTreeRootWithCompare,
390 const_cast<IntrusiveRedBlackTreeRootWithCompare*>(
391 static_cast<const IntrusiveRedBlackTreeRootWithCompare*>(&this->impl.root)),
392 const_cast<IntrusiveRedBlackTreeNode*>(node));
393 }
394
395 IntrusiveRedBlackTreeNode* NFindImpl(const IntrusiveRedBlackTreeNode* node) const {
396 return RB_NFIND(
397 IntrusiveRedBlackTreeRootWithCompare,
398 const_cast<IntrusiveRedBlackTreeRootWithCompare*>(
399 static_cast<const IntrusiveRedBlackTreeRootWithCompare*>(&this->impl.root)),
400 const_cast<IntrusiveRedBlackTreeNode*>(node));
401 }
402
403 IntrusiveRedBlackTreeNode* FindLightImpl(const_light_pointer lelm) const {
404 return RB_FIND_LIGHT(
405 IntrusiveRedBlackTreeRootWithCompare,
406 const_cast<IntrusiveRedBlackTreeRootWithCompare*>(
407 static_cast<const IntrusiveRedBlackTreeRootWithCompare*>(&this->impl.root)),
408 static_cast<const void*>(lelm));
409 }
410
411 IntrusiveRedBlackTreeNode* NFindLightImpl(const_light_pointer lelm) const {
412 return RB_NFIND_LIGHT(
413 IntrusiveRedBlackTreeRootWithCompare,
414 const_cast<IntrusiveRedBlackTreeRootWithCompare*>(
415 static_cast<const IntrusiveRedBlackTreeRootWithCompare*>(&this->impl.root)),
416 static_cast<const void*>(lelm));
417 }
418
419public:
420 constexpr IntrusiveRedBlackTree() = default;
421
422 // Iterator accessors.
423 iterator begin() {
424 return iterator(this->impl.begin());
425 }
426
427 const_iterator begin() const {
428 return const_iterator(this->impl.begin());
429 }
430
431 iterator end() {
432 return iterator(this->impl.end());
433 }
434
435 const_iterator end() const {
436 return const_iterator(this->impl.end());
437 }
438
439 const_iterator cbegin() const {
440 return this->begin();
441 }
442
443 const_iterator cend() const {
444 return this->end();
445 }
446
447 iterator iterator_to(reference ref) {
448 return iterator(this->impl.iterator_to(*Traits::GetNode(std::addressof(ref))));
449 }
450
451 const_iterator iterator_to(const_reference ref) const {
452 return const_iterator(this->impl.iterator_to(*Traits::GetNode(std::addressof(ref))));
453 }
454
455 // Content management.
456 bool empty() const {
457 return this->impl.empty();
458 }
459
460 reference back() {
461 return *Traits::GetParent(std::addressof(this->impl.back()));
462 }
463
464 const_reference back() const {
465 return *Traits::GetParent(std::addressof(this->impl.back()));
466 }
467
468 reference front() {
469 return *Traits::GetParent(std::addressof(this->impl.front()));
470 }
471
472 const_reference front() const {
473 return *Traits::GetParent(std::addressof(this->impl.front()));
474 }
475
476 iterator erase(iterator it) {
477 return iterator(this->impl.erase(it.GetImplIterator()));
478 }
479
480 iterator insert(reference ref) {
481 ImplType::pointer node = Traits::GetNode(std::addressof(ref));
482 this->InsertImpl(node);
483 return iterator(node);
484 }
485
486 iterator find(const_reference ref) const {
487 return iterator(this->FindImpl(Traits::GetNode(std::addressof(ref))));
488 }
489
490 iterator nfind(const_reference ref) const {
491 return iterator(this->NFindImpl(Traits::GetNode(std::addressof(ref))));
492 }
493
494 iterator find_light(const_light_reference ref) const {
495 return iterator(this->FindLightImpl(std::addressof(ref)));
496 }
497
498 iterator nfind_light(const_light_reference ref) const {
499 return iterator(this->NFindLightImpl(std::addressof(ref)));
500 }
501};
502
503template <auto T, class Derived = impl::GetParentType<T>>
504class IntrusiveRedBlackTreeMemberTraits;
505
506template <class Parent, IntrusiveRedBlackTreeNode Parent::*Member, class Derived>
507class IntrusiveRedBlackTreeMemberTraits<Member, Derived> {
508public:
509 template <class Comparator>
510 using TreeType = IntrusiveRedBlackTree<Derived, IntrusiveRedBlackTreeMemberTraits, Comparator>;
511 using TreeTypeImpl = impl::IntrusiveRedBlackTreeImpl;
512
513private:
514 template <class, class, class>
515 friend class IntrusiveRedBlackTree;
516
517 friend class impl::IntrusiveRedBlackTreeImpl;
518
519 static constexpr IntrusiveRedBlackTreeNode* GetNode(Derived* parent) {
520 return std::addressof(parent->*Member);
521 }
522
523 static constexpr IntrusiveRedBlackTreeNode const* GetNode(Derived const* parent) {
524 return std::addressof(parent->*Member);
525 }
526
527 static constexpr Derived* GetParent(IntrusiveRedBlackTreeNode* node) {
528 return GetParentPointer<Member, Derived>(node);
529 }
530
531 static constexpr Derived const* GetParent(const IntrusiveRedBlackTreeNode* node) {
532 return GetParentPointer<Member, Derived>(node);
533 }
534
535private:
536 static constexpr TYPED_STORAGE(Derived) DerivedStorage = {};
537 static_assert(GetParent(GetNode(GetPointer(DerivedStorage))) == GetPointer(DerivedStorage));
538};
539
540template <auto T, class Derived = impl::GetParentType<T>>
541class IntrusiveRedBlackTreeMemberTraitsDeferredAssert;
542
543template <class Parent, IntrusiveRedBlackTreeNode Parent::*Member, class Derived>
544class IntrusiveRedBlackTreeMemberTraitsDeferredAssert<Member, Derived> {
545public:
546 template <class Comparator>
547 using TreeType =
548 IntrusiveRedBlackTree<Derived, IntrusiveRedBlackTreeMemberTraitsDeferredAssert, Comparator>;
549 using TreeTypeImpl = impl::IntrusiveRedBlackTreeImpl;
550
551 static constexpr bool IsValid() {
552 TYPED_STORAGE(Derived) DerivedStorage = {};
553 return GetParent(GetNode(GetPointer(DerivedStorage))) == GetPointer(DerivedStorage);
554 }
555
556private:
557 template <class, class, class>
558 friend class IntrusiveRedBlackTree;
559
560 friend class impl::IntrusiveRedBlackTreeImpl;
561
562 static constexpr IntrusiveRedBlackTreeNode* GetNode(Derived* parent) {
563 return std::addressof(parent->*Member);
564 }
565
566 static constexpr IntrusiveRedBlackTreeNode const* GetNode(Derived const* parent) {
567 return std::addressof(parent->*Member);
568 }
569
570 static constexpr Derived* GetParent(IntrusiveRedBlackTreeNode* node) {
571 return GetParentPointer<Member, Derived>(node);
572 }
573
574 static constexpr Derived const* GetParent(const IntrusiveRedBlackTreeNode* node) {
575 return GetParentPointer<Member, Derived>(node);
576 }
577};
578
579template <class Derived>
580class IntrusiveRedBlackTreeBaseNode : public IntrusiveRedBlackTreeNode {
581public:
582 constexpr Derived* GetPrev() {
583 return static_cast<Derived*>(impl::IntrusiveRedBlackTreeImpl::GetPrev(this));
584 }
585 constexpr const Derived* GetPrev() const {
586 return static_cast<const Derived*>(impl::IntrusiveRedBlackTreeImpl::GetPrev(this));
587 }
588
589 constexpr Derived* GetNext() {
590 return static_cast<Derived*>(impl::IntrusiveRedBlackTreeImpl::GetNext(this));
591 }
592 constexpr const Derived* GetNext() const {
593 return static_cast<const Derived*>(impl::IntrusiveRedBlackTreeImpl::GetNext(this));
594 }
595};
596
597template <class Derived>
598class IntrusiveRedBlackTreeBaseTraits {
599public:
600 template <class Comparator>
601 using TreeType = IntrusiveRedBlackTree<Derived, IntrusiveRedBlackTreeBaseTraits, Comparator>;
602 using TreeTypeImpl = impl::IntrusiveRedBlackTreeImpl;
603
604private:
605 template <class, class, class>
606 friend class IntrusiveRedBlackTree;
607
608 friend class impl::IntrusiveRedBlackTreeImpl;
609
610 static constexpr IntrusiveRedBlackTreeNode* GetNode(Derived* parent) {
611 return static_cast<IntrusiveRedBlackTreeNode*>(parent);
612 }
613
614 static constexpr IntrusiveRedBlackTreeNode const* GetNode(Derived const* parent) {
615 return static_cast<const IntrusiveRedBlackTreeNode*>(parent);
616 }
617
618 static constexpr Derived* GetParent(IntrusiveRedBlackTreeNode* node) {
619 return static_cast<Derived*>(node);
620 }
621
622 static constexpr Derived const* GetParent(const IntrusiveRedBlackTreeNode* node) {
623 return static_cast<const Derived*>(node);
624 }
625};
626
627} // namespace Common