mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-05 00:36:57 +00:00
561 lines
13 KiB
C++
561 lines
13 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#ifndef COMMON_RB_TREE_H
|
|
#define COMMON_RB_TREE_H
|
|
|
|
#include "common/func.h"
|
|
#include "common/util.h"
|
|
#include "common/scummsys.h"
|
|
|
|
namespace Common {
|
|
|
|
template<typename Key, typename Val>
|
|
struct PairFirst {
|
|
const Key &operator()(const Pair<Key, Val> &p) {
|
|
return p.first;
|
|
}
|
|
};
|
|
|
|
template<typename T>
|
|
struct Identity {
|
|
const T &operator()(const T &t) {
|
|
return t;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @defgroup common_rb_tree Red-black tree
|
|
* @ingroup common
|
|
*
|
|
* @brief API for operating on a red black tree.
|
|
*
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* Red-black tree implementation with insertion and deletion algorithms based on the ones
|
|
* found in Introduction to Algorithms by Cormen, Leiserson, Rivest and Stein.
|
|
* Used in the implementation of Common::StableMap and Common::MultiMap
|
|
*/
|
|
template<class ValueType, class Key, class KeyProj, class KeyComp = Common::Less<Key> >
|
|
class RBTree {
|
|
public:
|
|
enum class Color {
|
|
kRed,
|
|
kBlack,
|
|
};
|
|
|
|
struct Node {
|
|
Node *parent;
|
|
Node *left;
|
|
Node *right;
|
|
Color color;
|
|
ValueType value;
|
|
};
|
|
|
|
template<typename Ref, typename Ptr>
|
|
class Iterator {
|
|
public:
|
|
friend RBTree;
|
|
|
|
Iterator() = default;
|
|
Iterator(const Iterator &) = default;
|
|
Iterator &operator=(const Iterator &) = default;
|
|
|
|
Ref operator*() const { return _current->value; }
|
|
|
|
Ptr operator->() const { return &_current->value; }
|
|
|
|
Iterator &operator++() {
|
|
if (_current->right) {
|
|
_current = leftmost(_current->right);
|
|
} else {
|
|
auto p = _current->parent;
|
|
while (p && p->right == _current) {
|
|
_current = p;
|
|
p = p->parent;
|
|
}
|
|
_current = p;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
Iterator operator++(int) {
|
|
auto temp = *this;
|
|
++(*this);
|
|
return temp;
|
|
}
|
|
|
|
bool operator==(const Iterator &rhs) const {
|
|
return _current == rhs._current;
|
|
}
|
|
|
|
bool operator!=(const Iterator &rhs) const {
|
|
return _current != rhs._current;
|
|
}
|
|
|
|
private:
|
|
explicit Iterator(Node *n) : _current(n) {}
|
|
|
|
Node *_current = nullptr;
|
|
};
|
|
|
|
using BasicIterator = Iterator<ValueType &, ValueType *>; /*!< RBTree iterator. */
|
|
using ConstIterator = Iterator<const ValueType &, const ValueType *>; /*!< Const-qualified RBTree iterator. */
|
|
|
|
RBTree(KeyComp comp = {}) : _comp(Common::move(comp)) {
|
|
}
|
|
|
|
/** Construct an RBTree as a copy of the given tree @p other . */
|
|
RBTree(const RBTree &other) : _comp(other._comp) {
|
|
for (const auto &val : other)
|
|
insert(val);
|
|
}
|
|
|
|
/** Construct an RBTree by moving the contents of the given tree (using the C++11 move semantics). */
|
|
RBTree(RBTree &&other) : _root(other._root), _leftmost(other._leftmost), _size(other._size), _comp(Common::move(other._comp)) {
|
|
}
|
|
|
|
/** Assign the given tree to this tree. */
|
|
RBTree &operator=(const RBTree &rhs) {
|
|
*this = RBTree(rhs);
|
|
return *this;
|
|
}
|
|
|
|
/** Moves the contents of the given tree into this tree (using the C++11 move semantics). */
|
|
RBTree &operator=(RBTree &&rhs) {
|
|
clear();
|
|
_root = rhs._root;
|
|
_leftmost = rhs._leftmost;
|
|
_size = rhs._size;
|
|
_comp = Common::move(rhs._comp);
|
|
rhs._root = nullptr;
|
|
rhs._leftmost = nullptr;
|
|
rhs._size = 0;
|
|
return *this;
|
|
}
|
|
|
|
/** Clears the contents of the tree. */
|
|
void clear() {
|
|
erase(begin(), end());
|
|
_size = 0;
|
|
_root = nullptr;
|
|
_leftmost = nullptr;
|
|
}
|
|
|
|
/** Return an iterator pointing to the first element in the tree. */
|
|
BasicIterator begin() { return BasicIterator{_leftmost}; }
|
|
|
|
/** Return a const iterator pointing to the first element of the tree. */
|
|
ConstIterator begin() const { return ConstIterator{_leftmost}; }
|
|
|
|
/** Return an iterator pointing to the last element in the tree. */
|
|
BasicIterator end() { return BasicIterator{nullptr}; }
|
|
|
|
/** Return a const iterator pointing to the last element of the tree. */
|
|
ConstIterator end() const { return ConstIterator{nullptr}; }
|
|
|
|
/**
|
|
* Returns an iterator to the first item thas is not less than @p key
|
|
* in the tree (or end() if this cannot be found).
|
|
*/
|
|
BasicIterator lowerBound(const Key &key) {
|
|
Node *it = _root;
|
|
Node *res = nullptr;
|
|
while (it) {
|
|
if (!_comp(KeyProj()(it->value), key)) {
|
|
res = it;
|
|
it = it->left;
|
|
} else {
|
|
it = it->right;
|
|
}
|
|
}
|
|
return BasicIterator{res};
|
|
}
|
|
|
|
/**
|
|
* Returns a const iterator to the first item thas is not less than @p key
|
|
* in the tree (or end() if this cannot be found).
|
|
*/
|
|
ConstIterator lowerBound(const Key &key) const {
|
|
Node *it = _root;
|
|
Node *res = nullptr;
|
|
while (it) {
|
|
if (!_comp(KeyProj()(it->value), key)) {
|
|
res = it;
|
|
it = it->left;
|
|
} else {
|
|
it = it->right;
|
|
}
|
|
}
|
|
return ConstIterator{res};
|
|
}
|
|
|
|
/**
|
|
* Returns an iterator to the first item bigger than @p key
|
|
* in the tree (or end() if this cannot be found).
|
|
*/
|
|
BasicIterator upperBound(const Key &key) {
|
|
Node *it = _root;
|
|
Node *res = nullptr;
|
|
while (it) {
|
|
if (!_comp(key, KeyProj()(it->value))) {
|
|
it = it->right;
|
|
} else {
|
|
res = it;
|
|
it = it->left;
|
|
}
|
|
}
|
|
return BasicIterator{res};
|
|
}
|
|
|
|
/**
|
|
* Return a const iterator to the first item bigger than @p key
|
|
* in the tree (or end() if this cannot be found).
|
|
*/
|
|
ConstIterator upperBound(const Key &key) const {
|
|
Node *it = _root;
|
|
Node *res = nullptr;
|
|
while (it) {
|
|
if (!_comp(key, KeyProj()(it->value))) {
|
|
it = it->right;
|
|
} else {
|
|
res = it;
|
|
it = it->left;
|
|
}
|
|
}
|
|
return ConstIterator{res};
|
|
}
|
|
|
|
/** Erases the item in the tree pointed by @p it .*/
|
|
BasicIterator erase(BasicIterator it) {
|
|
Node *const z = it._current;
|
|
Node *y = z;
|
|
assert(y);
|
|
const auto ret = it++;
|
|
Color y_prev_color = y->color;
|
|
Node *x;
|
|
Node *xp = nullptr;
|
|
if (!y->left) {
|
|
x = y->right;
|
|
xp = y->parent; // since x is put in y's place by the next call
|
|
transplant(y, y->right);
|
|
} else if (!y->right) {
|
|
x = y->left;
|
|
xp = y->parent;
|
|
transplant(y, y->left);
|
|
} else {
|
|
y = leftmost(z->right);
|
|
y_prev_color = y->color;
|
|
x = y->right;
|
|
if (y != z->right) {
|
|
xp = y->parent;
|
|
transplant(y, y->right);
|
|
y->right = z->right;
|
|
y->right->parent = y;
|
|
} else {
|
|
xp = y;
|
|
}
|
|
transplant(z, y);
|
|
y->left = z->left;
|
|
y->left->parent = y;
|
|
y->color = z->color;
|
|
}
|
|
if (y_prev_color == Color::kBlack)
|
|
fixDelete(x, xp);
|
|
delete z;
|
|
--_size;
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Erase the elements from @p first to @p last and return an iterator pointing to the next element in the tree.
|
|
* @note
|
|
* If [first, last) is not a valid range for the tree, the behaviour is undefined.
|
|
*/
|
|
BasicIterator erase(BasicIterator first, BasicIterator last) {
|
|
while (first != last)
|
|
erase(first++);
|
|
return last;
|
|
}
|
|
|
|
/** Inserts a value @p val into the tree returning an iterator for the inserted value. */
|
|
BasicIterator insert(const ValueType &val) {
|
|
return internalInsert(&_root, val);
|
|
}
|
|
|
|
/**
|
|
* Inserts the element @p val starting from @p start instead of the tree's root.
|
|
* This operations is meant for efficient insertions after a call to lowerBound.
|
|
* For example:
|
|
* @code
|
|
* auto it = tree.lowerBound(value);
|
|
* if (it == tree.end() || *it != value)
|
|
* tree.insert(it, value);
|
|
* @endcode
|
|
* inserts 'value' if its not contained in 'tree' (assumes that key and value type are the same)
|
|
* @note
|
|
* If @p start is not the lower bound, or it's not end(),
|
|
* the resulting tree could be unsorted.
|
|
*/
|
|
BasicIterator insert(BasicIterator start, const ValueType &val) {
|
|
if (start == end())
|
|
return insert(val);
|
|
return internalInsert(&start._current, val);
|
|
}
|
|
|
|
/** Returns the number of values in the tree. */
|
|
size_t size() const { return _size; }
|
|
|
|
/**
|
|
* Returns true if the tree is empty.
|
|
* Shorthand for:
|
|
* @code
|
|
* tree.size() == 0
|
|
* @endcode
|
|
*/
|
|
bool isEmpty() const { return _size == 0; }
|
|
|
|
~RBTree() { clear(); }
|
|
|
|
private:
|
|
KeyComp _comp;
|
|
Node *_root = nullptr;
|
|
Node *_leftmost = nullptr;
|
|
size_t _size = 0;
|
|
|
|
BasicIterator internalInsert(Node **starting_point, const ValueType &val) {
|
|
auto it = starting_point;
|
|
Node *parent = nullptr;
|
|
while (*it) {
|
|
parent = *it;
|
|
if (_comp(KeyProj()((*it)->value), KeyProj()(val))) {
|
|
it = &(*it)->right;
|
|
} else {
|
|
it = &(*it)->left;
|
|
}
|
|
}
|
|
*it = new Node{
|
|
parent,
|
|
nullptr,
|
|
nullptr,
|
|
Color::kRed,
|
|
val,
|
|
};
|
|
if (!_leftmost || (parent == _leftmost && _leftmost->left == *it))
|
|
_leftmost = *it;
|
|
++_size;
|
|
auto ret = BasicIterator{*it};
|
|
fixInsert(*it);
|
|
return ret;
|
|
}
|
|
|
|
static Node *leftmost(Node *n) {
|
|
while (n->left)
|
|
n = n->left;
|
|
return n;
|
|
}
|
|
|
|
// neither rotate changes _leftmost
|
|
void rotateLeft(Node *t) {
|
|
assert(t);
|
|
assert(t->right);
|
|
Node *r = t->right;
|
|
Node *p = t->parent;
|
|
// set r->left as t->right
|
|
t->right = r->left;
|
|
if (r->left)
|
|
r->left->parent = t;
|
|
// set the parent of r
|
|
r->parent = p;
|
|
if (!p)
|
|
_root = r;
|
|
else if (p->right == t)
|
|
p->right = r;
|
|
else
|
|
p->left = r;
|
|
// set the parent of t
|
|
t->parent = r;
|
|
r->left = t;
|
|
}
|
|
|
|
void rotateRight(Node *t) {
|
|
assert(t);
|
|
assert(t->left);
|
|
Node *l = t->left;
|
|
Node *p = t->parent;
|
|
assert(p != l);
|
|
// set l->right as t->left
|
|
t->left = l->right;
|
|
if (l->right)
|
|
l->right->parent = t;
|
|
// set the parent of l
|
|
l->parent = p;
|
|
if (!p)
|
|
_root = l;
|
|
else if (p->right == t)
|
|
p->right = l;
|
|
else
|
|
p->left = l;
|
|
// set the parent of t
|
|
l->right = t;
|
|
t->parent = l;
|
|
}
|
|
|
|
void transplant(Node *t, Node *u) {
|
|
if (!t->parent) {
|
|
_root = u;
|
|
} else if (t == t->parent->left) {
|
|
t->parent->left = u;
|
|
} else {
|
|
t->parent->right = u;
|
|
}
|
|
if (u) {
|
|
u->parent = t->parent;
|
|
}
|
|
if (t == _leftmost)
|
|
_leftmost = u ? leftmost(u) : t->parent;
|
|
}
|
|
|
|
void fixInsert(Node *t) {
|
|
while (t->parent && t->parent->color == Color::kRed) {
|
|
Node *p = t->parent;
|
|
Node *g = p->parent;
|
|
// cannot be null since p is not _root
|
|
assert(g);
|
|
if (p == g->left) {
|
|
Node *const u = g->right;
|
|
if (u && u->color == Color::kRed) {
|
|
p->color = u->color = Color::kBlack;
|
|
g->color = Color::kRed;
|
|
t = g;
|
|
} else {
|
|
if (t == p->right) {
|
|
rotateLeft(p);
|
|
t = p;
|
|
p = t->parent;
|
|
}
|
|
p->color = Color::kBlack;
|
|
// g is not changed by the previous rotation
|
|
g->color = Color::kRed;
|
|
rotateRight(g);
|
|
}
|
|
} else {
|
|
Node *const u = g->left;
|
|
if (u && u->color == Color::kRed) {
|
|
p->color = u->color = Color::kBlack;
|
|
g->color = Color::kRed;
|
|
t = g;
|
|
} else {
|
|
if (t == p->left) {
|
|
rotateRight(p);
|
|
t = p;
|
|
p = t->parent;
|
|
}
|
|
p->color = Color::kBlack;
|
|
g->color = Color::kRed;
|
|
rotateLeft(g);
|
|
}
|
|
}
|
|
}
|
|
_root->color = Color::kBlack;
|
|
}
|
|
|
|
void fixDelete(Node *t, Node *p) {
|
|
while (t != _root && (!t || t->color == Color::kBlack)) {
|
|
if (t == p->left) {
|
|
// since the deleted node was black and t is in its
|
|
// place, it has to have a sibling
|
|
Node *b = p->right;
|
|
assert(b);
|
|
if (b->color == Color::kRed) {
|
|
b->color = Color::kBlack;
|
|
p->color = Color::kRed;
|
|
rotateLeft(p);
|
|
p = b->left;
|
|
// since b was red, it had two black children,
|
|
// the right one now being p->right
|
|
b = p->right;
|
|
}
|
|
if ((!b->left || b->left->color == Color::kBlack) &&
|
|
(!b->right || b->right->color == Color::kBlack)) {
|
|
b->color = Color::kRed;
|
|
t = p;
|
|
p = p->parent;
|
|
} else {
|
|
if (!b->right || b->right->color == Color::kBlack) {
|
|
// b->left exists, since b->right is black, and it is red
|
|
// because of one of the above checks
|
|
b->left->color = Color::kBlack;
|
|
b->color = Color::kRed;
|
|
rotateRight(b);
|
|
b = p->right; // p is not changed by the rotation
|
|
}
|
|
b->color = p->color;
|
|
p->color = Color::kBlack;
|
|
if (b->right)
|
|
b->right->color = Color::kBlack;
|
|
rotateLeft(p);
|
|
break;
|
|
}
|
|
} else { // same as above case but left and right swapped
|
|
Node *b = p->left;
|
|
assert(b);
|
|
if (b->color == Color::kRed) {
|
|
b->color = Color::kBlack;
|
|
p->color = Color::kRed;
|
|
rotateRight(p);
|
|
p = b->right;
|
|
b = p->left;
|
|
}
|
|
if ((!b->left || b->left->color == Color::kBlack) &&
|
|
(!b->right || b->right->color == Color::kBlack)) {
|
|
b->color = Color::kRed;
|
|
t = p;
|
|
p = p->parent;
|
|
} else {
|
|
if (!b->left || b->left->color == Color::kBlack) {
|
|
b->right->color = Color::kBlack;
|
|
b->color = Color::kRed;
|
|
rotateLeft(b);
|
|
b = p->left;
|
|
}
|
|
b->color = p->color;
|
|
p->color = Color::kBlack;
|
|
if (b->left)
|
|
b->left->color = Color::kBlack;
|
|
rotateRight(p);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (t)
|
|
t->color = Color::kBlack;
|
|
}
|
|
};
|
|
|
|
/** @} */
|
|
|
|
} // End of namespace Common
|
|
|
|
#endif
|