Files
klubhaus-doorbell/libraries/FastLED/src/fl/rbtree.h
2026-02-12 00:45:31 -08:00

1020 lines
31 KiB
C++

#pragma once
#include "fl/assert.h"
#include "fl/comparators.h"
#include "fl/namespace.h"
#include "fl/pair.h"
#include "fl/type_traits.h"
#include "fl/type_traits.h"
#include "fl/algorithm.h"
#include "fl/allocator.h"
namespace fl {
// Generic Red-Black Tree implementation
// This is a self-balancing binary search tree with O(log n) operations
// T is the value type stored in the tree
// Compare is a comparator that can compare T values
template <typename T, typename Compare = less<T>, typename Allocator = allocator_slab<char>>
class RedBlackTree {
public:
class iterator;
class const_iterator;
using value_type = T;
using size_type = fl::size;
using difference_type = ptrdiff_t;
using compare_type = Compare;
using reference = value_type&;
using const_reference = const value_type&;
using pointer = value_type*;
using const_pointer = const value_type*;
using allocator_type = Allocator;
// Red-Black Tree colors
enum Color { RED, BLACK };
private:
struct RBNode {
value_type data;
Color color;
RBNode* left;
RBNode* right;
RBNode* parent;
RBNode(const value_type& val, Color c = RED, RBNode* p = nullptr)
: data(val), color(c), left(nullptr), right(nullptr), parent(p) {}
template<typename... Args>
RBNode(Color c, RBNode* p, Args&&... args)
: data(fl::forward<Args>(args)...), color(c), left(nullptr), right(nullptr), parent(p) {}
};
using NodeAllocator = typename Allocator::template rebind<RBNode>::other;
RBNode* root_;
fl::size size_;
Compare comp_;
NodeAllocator alloc_;
// Helper methods
void rotateLeft(RBNode* x) {
RBNode* y = x->right;
x->right = y->left;
if (y->left != nullptr) {
y->left->parent = x;
}
y->parent = x->parent;
if (x->parent == nullptr) {
root_ = y;
} else if (x == x->parent->left) {
x->parent->left = y;
} else {
x->parent->right = y;
}
y->left = x;
x->parent = y;
}
void rotateRight(RBNode* x) {
RBNode* y = x->left;
x->left = y->right;
if (y->right != nullptr) {
y->right->parent = x;
}
y->parent = x->parent;
if (x->parent == nullptr) {
root_ = y;
} else if (x == x->parent->right) {
x->parent->right = y;
} else {
x->parent->left = y;
}
y->right = x;
x->parent = y;
}
void insertFixup(RBNode* z) {
while (z->parent != nullptr && z->parent->parent != nullptr && z->parent->color == RED) {
if (z->parent == z->parent->parent->left) {
RBNode* y = z->parent->parent->right;
if (y != nullptr && y->color == RED) {
z->parent->color = BLACK;
y->color = BLACK;
z->parent->parent->color = RED;
z = z->parent->parent;
} else {
if (z == z->parent->right) {
z = z->parent;
rotateLeft(z);
}
z->parent->color = BLACK;
z->parent->parent->color = RED;
rotateRight(z->parent->parent);
}
} else {
RBNode* y = z->parent->parent->left;
if (y != nullptr && y->color == RED) {
z->parent->color = BLACK;
y->color = BLACK;
z->parent->parent->color = RED;
z = z->parent->parent;
} else {
if (z == z->parent->left) {
z = z->parent;
rotateRight(z);
}
z->parent->color = BLACK;
z->parent->parent->color = RED;
rotateLeft(z->parent->parent);
}
}
}
root_->color = BLACK;
}
void transplant(RBNode* u, RBNode* v) {
if (u->parent == nullptr) {
root_ = v;
} else if (u == u->parent->left) {
u->parent->left = v;
} else {
u->parent->right = v;
}
if (v != nullptr) {
v->parent = u->parent;
}
}
RBNode* minimum(RBNode* x) const {
while (x->left != nullptr) {
x = x->left;
}
return x;
}
RBNode* maximum(RBNode* x) const {
while (x->right != nullptr) {
x = x->right;
}
return x;
}
// Fixed to properly use xParent when x is nullptr; removes unused parameter warning and centralizes erase fixup
void deleteFixup(RBNode* x, RBNode* xParent) {
while ((x != root_) && (x == nullptr || x->color == BLACK)) {
if (x == (xParent ? xParent->left : nullptr)) {
RBNode* w = xParent ? xParent->right : nullptr;
if (w && w->color == RED) {
w->color = BLACK;
if (xParent) { xParent->color = RED; rotateLeft(xParent); }
w = xParent ? xParent->right : nullptr;
}
bool wLeftBlack = (!w || !w->left || w->left->color == BLACK);
bool wRightBlack = (!w || !w->right || w->right->color == BLACK);
if (wLeftBlack && wRightBlack) {
if (w) w->color = RED;
x = xParent;
xParent = xParent ? xParent->parent : nullptr;
} else {
if (!w || (w->right == nullptr || w->right->color == BLACK)) {
if (w && w->left) w->left->color = BLACK;
if (w) { w->color = RED; rotateRight(w); }
w = xParent ? xParent->right : nullptr;
}
if (w) w->color = xParent ? xParent->color : BLACK;
if (xParent) xParent->color = BLACK;
if (w && w->right) w->right->color = BLACK;
if (xParent) rotateLeft(xParent);
x = root_;
}
} else {
RBNode* w = xParent ? xParent->left : nullptr;
if (w && w->color == RED) {
w->color = BLACK;
if (xParent) { xParent->color = RED; rotateRight(xParent); }
w = xParent ? xParent->left : nullptr;
}
bool wRightBlack = (!w || !w->right || w->right->color == BLACK);
bool wLeftBlack = (!w || !w->left || w->left->color == BLACK);
if (wRightBlack && wLeftBlack) {
if (w) w->color = RED;
x = xParent;
xParent = xParent ? xParent->parent : nullptr;
} else {
if (!w || (w->left == nullptr || w->left->color == BLACK)) {
if (w && w->right) w->right->color = BLACK;
if (w) { w->color = RED; rotateLeft(w); }
w = xParent ? xParent->left : nullptr;
}
if (w) w->color = xParent ? xParent->color : BLACK;
if (xParent) xParent->color = BLACK;
if (w && w->left) w->left->color = BLACK;
if (xParent) rotateRight(xParent);
x = root_;
}
}
}
if (x) x->color = BLACK;
}
RBNode* findNode(const value_type& value) const {
RBNode* current = root_;
while (current != nullptr) {
if (comp_(value, current->data)) {
current = current->left;
} else if (comp_(current->data, value)) {
current = current->right;
} else {
return current;
}
}
return nullptr;
}
void destroyTree(RBNode* node) {
if (node != nullptr) {
destroyTree(node->left);
destroyTree(node->right);
alloc_.destroy(node);
alloc_.deallocate(node, 1);
}
}
RBNode* copyTree(RBNode* node, RBNode* parent = nullptr) {
if (node == nullptr) return nullptr;
RBNode* newNode = alloc_.allocate(1);
if (newNode == nullptr) {
return nullptr;
}
alloc_.construct(newNode, node->data, node->color, parent);
newNode->left = copyTree(node->left, newNode);
newNode->right = copyTree(node->right, newNode);
return newNode;
}
// Shared insert implementation to reduce duplication
template <typename U>
fl::pair<iterator, bool> insertImpl(U&& value) {
RBNode* parent = nullptr;
RBNode* current = root_;
while (current != nullptr) {
parent = current;
if (comp_(value, current->data)) {
current = current->left;
} else if (comp_(current->data, value)) {
current = current->right;
} else {
return fl::pair<iterator, bool>(iterator(current, this), false);
}
}
RBNode* newNode = alloc_.allocate(1);
if (newNode == nullptr) {
return fl::pair<iterator, bool>(end(), false);
}
alloc_.construct(newNode, fl::forward<U>(value), RED, parent);
if (parent == nullptr) {
root_ = newNode;
} else if (comp_(newNode->data, parent->data)) {
parent->left = newNode;
} else {
parent->right = newNode;
}
insertFixup(newNode);
++size_;
return fl::pair<iterator, bool>(iterator(newNode, this), true);
}
// Bound helpers to avoid duplication between const/non-const
RBNode* lowerBoundNode(const value_type& value) const {
RBNode* current = root_;
RBNode* result = nullptr;
while (current != nullptr) {
if (!comp_(current->data, value)) {
result = current;
current = current->left;
} else {
current = current->right;
}
}
return result;
}
RBNode* upperBoundNode(const value_type& value) const {
RBNode* current = root_;
RBNode* result = nullptr;
while (current != nullptr) {
if (comp_(value, current->data)) {
result = current;
current = current->left;
} else {
current = current->right;
}
}
return result;
}
public:
// Iterator implementation
class iterator {
friend class RedBlackTree;
friend class const_iterator;
public:
using value_type = T;
private:
RBNode* node_;
const RedBlackTree* mTree;
RBNode* successor(RBNode* x) const {
if (x == nullptr) return nullptr;
if (x->right != nullptr) {
return mTree->minimum(x->right);
}
RBNode* y = x->parent;
while (y != nullptr && x == y->right) {
x = y;
y = y->parent;
}
return y;
}
RBNode* predecessor(RBNode* x) const {
if (x == nullptr) return nullptr;
if (x->left != nullptr) {
return mTree->maximum(x->left);
}
RBNode* y = x->parent;
while (y != nullptr && x == y->left) {
x = y;
y = y->parent;
}
return y;
}
public:
iterator() : node_(nullptr), mTree(nullptr) {}
iterator(RBNode* n, const RedBlackTree* t) : node_(n), mTree(t) {}
value_type& operator*() const {
FASTLED_ASSERT(node_ != nullptr, "RedBlackTree::iterator: dereferencing end iterator");
return node_->data;
}
value_type* operator->() const {
FASTLED_ASSERT(node_ != nullptr, "RedBlackTree::iterator: dereferencing end iterator");
return &(node_->data);
}
iterator& operator++() {
if (node_) {
node_ = successor(node_);
}
return *this;
}
iterator operator++(int) {
iterator temp = *this;
++(*this);
return temp;
}
iterator& operator--() {
if (node_) {
node_ = predecessor(node_);
} else if (mTree && mTree->root_) {
node_ = mTree->maximum(mTree->root_);
}
return *this;
}
iterator operator--(int) {
iterator temp = *this;
--(*this);
return temp;
}
bool operator==(const iterator& other) const {
return node_ == other.node_;
}
bool operator!=(const iterator& other) const {
return node_ != other.node_;
}
};
class const_iterator {
friend class RedBlackTree;
friend class iterator;
private:
const RBNode* node_;
const RedBlackTree* mTree;
const RBNode* successor(const RBNode* x) const {
if (x == nullptr) return nullptr;
if (x->right != nullptr) {
return mTree->minimum(x->right);
}
const RBNode* y = x->parent;
while (y != nullptr && x == y->right) {
x = y;
y = y->parent;
}
return y;
}
const RBNode* predecessor(const RBNode* x) const {
if (x == nullptr) return nullptr;
if (x->left != nullptr) {
return mTree->maximum(x->left);
}
const RBNode* y = x->parent;
while (y != nullptr && x == y->left) {
x = y;
y = y->parent;
}
return y;
}
public:
const_iterator() : node_(nullptr), mTree(nullptr) {}
const_iterator(const RBNode* n, const RedBlackTree* t) : node_(n), mTree(t) {}
const_iterator(const iterator& it) : node_(it.node_), mTree(it.mTree) {}
const value_type& operator*() const {
FASTLED_ASSERT(node_ != nullptr, "RedBlackTree::iterator: dereferencing end iterator");
return node_->data;
}
const value_type* operator->() const {
FASTLED_ASSERT(node_ != nullptr, "RedBlackTree::iterator: dereferencing end iterator");
return &(node_->data);
}
const_iterator& operator++() {
if (node_) {
node_ = successor(node_);
}
return *this;
}
const_iterator operator++(int) {
const_iterator temp = *this;
++(*this);
return temp;
}
const_iterator& operator--() {
if (node_) {
node_ = predecessor(node_);
} else if (mTree && mTree->root_) {
// Decrementing from end() should give us the maximum element
node_ = mTree->maximum(mTree->root_);
}
return *this;
}
const_iterator operator--(int) {
const_iterator temp = *this;
--(*this);
return temp;
}
bool operator==(const const_iterator& other) const {
return node_ == other.node_;
}
bool operator!=(const const_iterator& other) const {
return node_ != other.node_;
}
};
// Constructors and destructor
RedBlackTree(const Compare& comp = Compare(), const Allocator& alloc = Allocator())
: root_(nullptr), size_(0), comp_(comp), alloc_(alloc) {}
RedBlackTree(const RedBlackTree& other)
: root_(nullptr), size_(other.size_), comp_(other.comp_), alloc_(other.alloc_) {
if (other.root_) {
root_ = copyTree(other.root_);
}
}
RedBlackTree& operator=(const RedBlackTree& other) {
if (this != &other) {
clear();
size_ = other.size_;
comp_ = other.comp_;
alloc_ = other.alloc_;
if (other.root_) {
root_ = copyTree(other.root_);
}
}
return *this;
}
~RedBlackTree() {
clear();
}
// Iterators
iterator begin() {
if (root_ == nullptr) return end();
return iterator(minimum(root_), this);
}
const_iterator begin() const {
if (root_ == nullptr) return end();
return const_iterator(minimum(root_), this);
}
const_iterator cbegin() const {
return begin();
}
iterator end() {
return iterator(nullptr, this);
}
const_iterator end() const {
return const_iterator(nullptr, this);
}
const_iterator cend() const {
return end();
}
// Capacity
bool empty() const { return size_ == 0; }
fl::size size() const { return size_; }
fl::size max_size() const { return fl::size(-1); }
// Modifiers
void clear() {
destroyTree(root_);
root_ = nullptr;
size_ = 0;
}
fl::pair<iterator, bool> insert(const value_type& value) {
return insertImpl(value);
}
fl::pair<iterator, bool> insert(value_type&& value) {
return insertImpl(fl::move(value));
}
template<typename... Args>
fl::pair<iterator, bool> emplace(Args&&... args) {
value_type value(fl::forward<Args>(args)...);
return insert(fl::move(value));
}
iterator erase(const_iterator pos) {
if (pos.node_ == nullptr) return end();
RBNode* nodeToDelete = const_cast<RBNode*>(pos.node_);
RBNode* successor = nullptr;
if (nodeToDelete->right != nullptr) {
successor = minimum(nodeToDelete->right);
} else {
RBNode* current = nodeToDelete;
RBNode* parent = current->parent;
while (parent != nullptr && current == parent->right) {
current = parent;
parent = parent->parent;
}
successor = parent;
}
RBNode* y = nodeToDelete;
RBNode* x = nullptr;
RBNode* xParent = nullptr;
Color originalColor = y->color;
if (nodeToDelete->left == nullptr) {
x = nodeToDelete->right;
xParent = nodeToDelete->parent;
transplant(nodeToDelete, nodeToDelete->right);
} else if (nodeToDelete->right == nullptr) {
x = nodeToDelete->left;
xParent = nodeToDelete->parent;
transplant(nodeToDelete, nodeToDelete->left);
} else {
y = minimum(nodeToDelete->right);
originalColor = y->color;
x = y->right;
if (y->parent == nodeToDelete) {
xParent = y;
if (x) x->parent = y;
} else {
xParent = y->parent;
transplant(y, y->right);
y->right = nodeToDelete->right;
y->right->parent = y;
}
transplant(nodeToDelete, y);
y->left = nodeToDelete->left;
y->left->parent = y;
y->color = nodeToDelete->color;
}
alloc_.destroy(nodeToDelete);
alloc_.deallocate(nodeToDelete, 1);
--size_;
if (originalColor == BLACK) {
deleteFixup(x, xParent);
}
return iterator(successor, this);
}
fl::size erase(const value_type& value) {
RBNode* node = findNode(value);
if (node == nullptr) return 0;
erase(const_iterator(node, this));
return 1;
}
void swap(RedBlackTree& other) {
fl::swap(root_, other.root_);
fl::swap(size_, other.size_);
fl::swap(comp_, other.comp_);
fl::swap(alloc_, other.alloc_);
}
// Lookup
fl::size count(const value_type& value) const {
return findNode(value) != nullptr ? 1 : 0;
}
iterator find(const value_type& value) {
RBNode* node = findNode(value);
return node ? iterator(node, this) : end();
}
const_iterator find(const value_type& value) const {
RBNode* node = findNode(value);
return node ? const_iterator(node, this) : end();
}
bool contains(const value_type& value) const {
return findNode(value) != nullptr;
}
fl::pair<iterator, iterator> equal_range(const value_type& value) {
iterator lower = lower_bound(value);
iterator upper = upper_bound(value);
return fl::pair<iterator, iterator>(lower, upper);
}
fl::pair<const_iterator, const_iterator> equal_range(const value_type& value) const {
const_iterator lower = lower_bound(value);
const_iterator upper = upper_bound(value);
return fl::pair<const_iterator, const_iterator>(lower, upper);
}
iterator lower_bound(const value_type& value) {
RBNode* n = lowerBoundNode(value);
return n ? iterator(n, this) : end();
}
const_iterator lower_bound(const value_type& value) const {
RBNode* n = lowerBoundNode(value);
return n ? const_iterator(n, this) : end();
}
iterator upper_bound(const value_type& value) {
RBNode* n = upperBoundNode(value);
return n ? iterator(n, this) : end();
}
const_iterator upper_bound(const value_type& value) const {
RBNode* n = upperBoundNode(value);
return n ? const_iterator(n, this) : end();
}
// Observers
compare_type value_comp() const {
return comp_;
}
// Comparison operators
bool operator==(const RedBlackTree& other) const {
if (size_ != other.size_) return false;
const_iterator it1 = begin();
const_iterator it2 = other.begin();
while (it1 != end() && it2 != other.end()) {
// Two values are equal if neither is less than the other
if (comp_(*it1, *it2) || comp_(*it2, *it1)) {
return false;
}
++it1;
++it2;
}
return it1 == end() && it2 == other.end();
}
bool operator!=(const RedBlackTree& other) const {
return !(*this == other);
}
};
// Specialized Red-Black Tree for key-value pairs (maps)
template <typename Key, typename Value, typename Compare = less<Key>, typename Allocator = allocator_slab<char>>
class MapRedBlackTree {
public:
using key_type = Key;
using mapped_type = Value;
using value_type = fl::pair<Key, Value>;
using size_type = fl::size;
using difference_type = ptrdiff_t;
using key_compare = Compare;
using reference = value_type&;
using const_reference = const value_type&;
using pointer = value_type*;
using const_pointer = const value_type*;
using allocator_type = Allocator;
private:
// Comparator for pairs that compares only the key
struct PairCompare {
Compare comp_;
PairCompare(const Compare& comp = Compare()) : comp_(comp) {}
bool operator()(const value_type& a, const value_type& b) const {
return comp_(a.first, b.first);
}
};
using TreeType = RedBlackTree<value_type, PairCompare, Allocator>;
TreeType mTree;
public:
using iterator = typename TreeType::iterator;
using const_iterator = typename TreeType::const_iterator;
// Constructors and destructor
MapRedBlackTree(const Compare& comp = Compare(), const Allocator& alloc = Allocator())
: mTree(PairCompare(comp), alloc) {}
MapRedBlackTree(const MapRedBlackTree& other) = default;
MapRedBlackTree& operator=(const MapRedBlackTree& other) = default;
~MapRedBlackTree() = default;
// Iterators
iterator begin() { return mTree.begin(); }
const_iterator begin() const { return mTree.begin(); }
const_iterator cbegin() const { return mTree.cbegin(); }
iterator end() { return mTree.end(); }
const_iterator end() const { return mTree.end(); }
const_iterator cend() const { return mTree.cend(); }
// Capacity
bool empty() const { return mTree.empty(); }
fl::size size() const { return mTree.size(); }
fl::size max_size() const { return mTree.max_size(); }
// Element access
Value& operator[](const Key& key) {
auto result = mTree.insert(value_type(key, Value()));
return result.first->second;
}
Value& at(const Key& key) {
auto it = mTree.find(value_type(key, Value()));
FASTLED_ASSERT(it != mTree.end(), "MapRedBlackTree::at: key not found");
return it->second;
}
const Value& at(const Key& key) const {
auto it = mTree.find(value_type(key, Value()));
FASTLED_ASSERT(it != mTree.end(), "MapRedBlackTree::at: key not found");
return it->second;
}
// Modifiers
void clear() { mTree.clear(); }
fl::pair<iterator, bool> insert(const value_type& value) {
return mTree.insert(value);
}
fl::pair<iterator, bool> insert(value_type&& value) {
return mTree.insert(fl::move(value));
}
template<typename... Args>
fl::pair<iterator, bool> emplace(Args&&... args) {
return mTree.emplace(fl::forward<Args>(args)...);
}
iterator erase(const_iterator pos) {
return mTree.erase(pos);
}
fl::size erase(const Key& key) {
return mTree.erase(value_type(key, Value()));
}
void swap(MapRedBlackTree& other) {
mTree.swap(other.mTree);
}
// Lookup
fl::size count(const Key& key) const {
return mTree.count(value_type(key, Value()));
}
iterator find(const Key& key) {
return mTree.find(value_type(key, Value()));
}
const_iterator find(const Key& key) const {
return mTree.find(value_type(key, Value()));
}
bool contains(const Key& key) const {
return mTree.contains(value_type(key, Value()));
}
fl::pair<iterator, iterator> equal_range(const Key& key) {
return mTree.equal_range(value_type(key, Value()));
}
fl::pair<const_iterator, const_iterator> equal_range(const Key& key) const {
return mTree.equal_range(value_type(key, Value()));
}
iterator lower_bound(const Key& key) {
return mTree.lower_bound(value_type(key, Value()));
}
const_iterator lower_bound(const Key& key) const {
return mTree.lower_bound(value_type(key, Value()));
}
iterator upper_bound(const Key& key) {
return mTree.upper_bound(value_type(key, Value()));
}
const_iterator upper_bound(const Key& key) const {
return mTree.upper_bound(value_type(key, Value()));
}
// Observers
key_compare key_comp() const {
return mTree.value_comp().comp_;
}
// Comparison operators
bool operator==(const MapRedBlackTree& other) const {
if (mTree.size() != other.mTree.size()) return false;
auto it1 = mTree.begin();
auto it2 = other.mTree.begin();
while (it1 != mTree.end() && it2 != other.mTree.end()) {
// Compare both key and value
if (it1->first != it2->first || it1->second != it2->second) {
return false;
}
++it1;
++it2;
}
return it1 == mTree.end() && it2 == other.mTree.end();
}
bool operator!=(const MapRedBlackTree& other) const {
return !(*this == other);
}
};
// Specialized Red-Black Tree for sets (just keys, no values)
template <typename Key, typename Compare = less<Key>, typename Allocator = allocator_slab<char>>
class SetRedBlackTree {
public:
using key_type = Key;
using value_type = Key;
using size_type = fl::size;
using difference_type = ptrdiff_t;
using key_compare = Compare;
using reference = const value_type&;
using const_reference = const value_type&;
using pointer = const value_type*;
using const_pointer = const value_type*;
using allocator_type = Allocator;
private:
using TreeType = RedBlackTree<Key, Compare, Allocator>;
TreeType mTree;
public:
using iterator = typename TreeType::const_iterator; // Set iterators are always const
using const_iterator = typename TreeType::const_iterator;
// Constructors and destructor
SetRedBlackTree(const Compare& comp = Compare(), const Allocator& alloc = Allocator())
: mTree(comp, alloc) {}
SetRedBlackTree(const SetRedBlackTree& other) = default;
SetRedBlackTree& operator=(const SetRedBlackTree& other) = default;
~SetRedBlackTree() = default;
// Iterators
const_iterator begin() const { return mTree.begin(); }
const_iterator cbegin() const { return mTree.cbegin(); }
const_iterator end() const { return mTree.end(); }
const_iterator cend() const { return mTree.cend(); }
// Capacity
bool empty() const { return mTree.empty(); }
fl::size size() const { return mTree.size(); }
fl::size max_size() const { return mTree.max_size(); }
// Modifiers
void clear() { mTree.clear(); }
fl::pair<const_iterator, bool> insert(const value_type& value) {
auto result = mTree.insert(value);
return fl::pair<const_iterator, bool>(result.first, result.second);
}
fl::pair<const_iterator, bool> insert(value_type&& value) {
auto result = mTree.insert(fl::move(value));
return fl::pair<const_iterator, bool>(result.first, result.second);
}
template<typename... Args>
fl::pair<const_iterator, bool> emplace(Args&&... args) {
auto result = mTree.emplace(fl::forward<Args>(args)...);
return fl::pair<const_iterator, bool>(result.first, result.second);
}
const_iterator erase(const_iterator pos) {
return mTree.erase(pos);
}
fl::size erase(const Key& key) {
return mTree.erase(key);
}
void swap(SetRedBlackTree& other) {
mTree.swap(other.mTree);
}
// Lookup
fl::size count(const Key& key) const {
return mTree.count(key);
}
const_iterator find(const Key& key) const {
return mTree.find(key);
}
bool contains(const Key& key) const {
return mTree.contains(key);
}
fl::pair<const_iterator, const_iterator> equal_range(const Key& key) const {
return mTree.equal_range(key);
}
const_iterator lower_bound(const Key& key) const {
return mTree.lower_bound(key);
}
const_iterator upper_bound(const Key& key) const {
return mTree.upper_bound(key);
}
// Observers
key_compare key_comp() const {
return mTree.value_comp();
}
// Comparison operators
bool operator==(const SetRedBlackTree& other) const {
return mTree == other.mTree;
}
bool operator!=(const SetRedBlackTree& other) const {
return mTree != other.mTree;
}
};
} // namespace fl