mirror of
https://github.com/libretro/scummvm.git
synced 2024-11-28 03:40:36 +00:00
COMMON: Add std::map and std::multimap replacements
moved from hpl1/std
This commit is contained in:
parent
996ae31916
commit
2c2cc1720b
167
common/multimap.h
Normal file
167
common/multimap.h
Normal file
@ -0,0 +1,167 @@
|
||||
/* 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_MULTIMAP_H
|
||||
#define COMMON_MULTIMAP_H
|
||||
|
||||
#include "common/util.h"
|
||||
#include "common/rb_tree.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
/**
|
||||
* multimap implementation meant as a drop-in replacement for the C++ standard library's std::multimap
|
||||
*/
|
||||
template<class Key, class Val, class CompFunc = Common::Less<Key> >
|
||||
class MultiMap {
|
||||
using TreeT = RBTree<Pair<Key, Val>, Key, PairFirst<Key, Val>, CompFunc>;
|
||||
|
||||
public:
|
||||
using value_type = Pair<Key, Val>;
|
||||
using iterator = typename TreeT::BasicIterator;
|
||||
using const_iterator = typename TreeT::ConstIterator;
|
||||
|
||||
/**
|
||||
* Clears the map
|
||||
*/
|
||||
void clear() {
|
||||
_items.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the iterator start
|
||||
*/
|
||||
iterator begin() {
|
||||
return _items.begin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the iterator end
|
||||
*/
|
||||
iterator end() {
|
||||
return _items.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the const iterator start
|
||||
*/
|
||||
const_iterator begin() const {
|
||||
return _items.begin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the const iterator end
|
||||
*/
|
||||
const_iterator end() const {
|
||||
return _items.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator for the first element of the map that is
|
||||
* not less than the given key
|
||||
*/
|
||||
const_iterator lower_bound(const Key &key) const {
|
||||
return _items.lowerBound(key);
|
||||
}
|
||||
|
||||
iterator lower_bound(const Key &key) {
|
||||
return _items.lowerBound(key);
|
||||
}
|
||||
|
||||
iterator upper_bound(const Key &key) {
|
||||
return _items.upperBound(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the entry with the given key
|
||||
*/
|
||||
iterator find(const Key &theKey) {
|
||||
iterator it = _items.lowerBound(theKey);
|
||||
if (it != this->end() && compareEqual(it->first, theKey))
|
||||
return it;
|
||||
return this->end();
|
||||
}
|
||||
|
||||
const_iterator find(const Key &theKey) const {
|
||||
const_iterator it = _items.lowerBound(theKey);
|
||||
if (it != this->end() && compareEqual(it->first, theKey))
|
||||
return it;
|
||||
return this->end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Erases an entry in the map
|
||||
*/
|
||||
iterator erase(iterator it) {
|
||||
return _items.erase(it);
|
||||
}
|
||||
|
||||
iterator erase(iterator first, iterator last) {
|
||||
return _items.erase(first, last);
|
||||
}
|
||||
|
||||
iterator erase(const Key &theKey) {
|
||||
const iterator first = find(theKey);
|
||||
iterator last = first;
|
||||
while (last != this->end() && compareEqual(last->first, theKey))
|
||||
++last;
|
||||
return _items.erase(first, last);
|
||||
}
|
||||
|
||||
iterator insert(const value_type &val) {
|
||||
return _items.insert(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the map
|
||||
*/
|
||||
size_t size() const {
|
||||
return _items.size();
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return _items.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of elements with a matching key
|
||||
*/
|
||||
size_t count(const Key &theKey) {
|
||||
int count_ = 0;
|
||||
for (iterator it = this->begin(); it != this->end(); ++it) {
|
||||
if (compareEqual(it->first, theKey))
|
||||
++count_;
|
||||
}
|
||||
return count_;
|
||||
}
|
||||
|
||||
private:
|
||||
bool compareEqual(const Key &a, const Key &b) {
|
||||
return !_comp(a, b) && !_comp(b, a);
|
||||
}
|
||||
|
||||
TreeT _items;
|
||||
CompFunc _comp;
|
||||
};
|
||||
|
||||
} // End of namespace Common
|
||||
|
||||
#endif
|
511
common/rb_tree.h
Normal file
511
common/rb_tree.h
Normal file
@ -0,0 +1,511 @@
|
||||
/* 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;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 *>;
|
||||
using ConstIterator = Iterator<const ValueType &, const ValueType *>;
|
||||
|
||||
RBTree(KeyComp comp = {}) : _comp(Common::move(comp)) {
|
||||
}
|
||||
|
||||
RBTree(const RBTree &other) : _comp(other._comp) {
|
||||
for (const auto &val : other)
|
||||
insert(val);
|
||||
}
|
||||
|
||||
RBTree(RBTree &&other) : _root(other._root), _leftmost(other._leftmost), _size(other._size), _comp(Common::move(other._comp)) {
|
||||
}
|
||||
|
||||
RBTree &operator=(const RBTree &rhs) {
|
||||
*this = RBTree(rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
erase(begin(), end());
|
||||
_size = 0;
|
||||
_root = nullptr;
|
||||
_leftmost = nullptr;
|
||||
}
|
||||
|
||||
BasicIterator begin() { return BasicIterator{_leftmost}; }
|
||||
|
||||
ConstIterator begin() const { return ConstIterator{_leftmost}; }
|
||||
|
||||
BasicIterator end() { return BasicIterator{nullptr}; }
|
||||
|
||||
ConstIterator end() const { return ConstIterator{nullptr}; }
|
||||
|
||||
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};
|
||||
}
|
||||
|
||||
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};
|
||||
}
|
||||
|
||||
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};
|
||||
}
|
||||
|
||||
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};
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
BasicIterator erase(BasicIterator first, BasicIterator last) {
|
||||
while (first != last)
|
||||
erase(first++);
|
||||
return last;
|
||||
}
|
||||
|
||||
BasicIterator insert(const ValueType &val) {
|
||||
return internalInsert(&_root, val);
|
||||
}
|
||||
|
||||
// requires that either start is lowerbound of val or start is end()
|
||||
// otherwise the resulting tree could be unsorted
|
||||
BasicIterator insert(BasicIterator start, const ValueType &val) {
|
||||
if (start == end())
|
||||
return insert(val);
|
||||
return internalInsert(&start._current, val);
|
||||
}
|
||||
|
||||
size_t size() const { return _size; }
|
||||
|
||||
bool isEmpty() const { return _size == 0; }
|
||||
|
||||
~RBTree() { clear(); }
|
||||
|
||||
private:
|
||||
KeyComp _comp;
|
||||
Node *_root = nullptr;
|
||||
Node *_leftmost = nullptr;
|
||||
size_t _size = 0;
|
||||
|
||||
Node *merge(Node *left, Node *right) {
|
||||
if (!right)
|
||||
return left;
|
||||
else if (!left)
|
||||
return right;
|
||||
else {
|
||||
auto lm = leftmost(right);
|
||||
lm->left = left;
|
||||
left->parent = lm;
|
||||
return right;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
179
common/stablemap.h
Normal file
179
common/stablemap.h
Normal file
@ -0,0 +1,179 @@
|
||||
/* 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_STABLEMAP_H
|
||||
#define COMMON_STABLEMAP_H
|
||||
|
||||
#include "common/rb_tree.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
/**
|
||||
* associative container meant as a drop-in replacement the C++ standard library's std::map
|
||||
*/
|
||||
template<class Key, class Val, class CompFunc = Common::Less<Key> >
|
||||
class StableMap {
|
||||
using TreeT = RBTree<Pair<Key, Val>, Key, PairFirst<Key, Val>, CompFunc>;
|
||||
|
||||
public:
|
||||
using value_type = Pair<Key, Val>;
|
||||
using iterator = typename TreeT::BasicIterator;
|
||||
using const_iterator = typename TreeT::ConstIterator;
|
||||
|
||||
/**
|
||||
* Clears the map
|
||||
*/
|
||||
void clear() {
|
||||
_items.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the iterator start
|
||||
*/
|
||||
iterator begin() {
|
||||
return _items.begin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the iterator end
|
||||
*/
|
||||
iterator end() {
|
||||
return _items.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the const iterator start
|
||||
*/
|
||||
const_iterator begin() const {
|
||||
return _items.begin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the const iterator end
|
||||
*/
|
||||
const_iterator end() const {
|
||||
return _items.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator for the first element of the map that is
|
||||
* not less than the given key
|
||||
*/
|
||||
const_iterator lower_bound(const Key &key) const {
|
||||
return _items.lowerBound(key);
|
||||
}
|
||||
|
||||
iterator lower_bound(const Key &key) {
|
||||
return _items.lowerBound(key);
|
||||
}
|
||||
|
||||
iterator upper_bound(const Key &key) {
|
||||
return _items.upperBound(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the entry with the given key
|
||||
*/
|
||||
iterator find(const Key &theKey) {
|
||||
iterator it = _items.lowerBound(theKey);
|
||||
if (it != this->end() && compareEqual(it->first, theKey))
|
||||
return it;
|
||||
return this->end();
|
||||
}
|
||||
|
||||
const_iterator find(const Key &theKey) const {
|
||||
const_iterator it = _items.lowerBound(theKey);
|
||||
if (it != this->end() && compareEqual(it->first, theKey))
|
||||
return it;
|
||||
return this->end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Square brackets operator accesses items by key, creating if necessary
|
||||
*/
|
||||
Val &operator[](const Key &theKey) {
|
||||
iterator it = _items.lowerBound(theKey);
|
||||
if (it == this->end() || !compareEqual(it->first, theKey)) {
|
||||
return _items.insert(theKey).second;
|
||||
}
|
||||
return *it->second;
|
||||
}
|
||||
|
||||
/**
|
||||
* Erases an entry in the map
|
||||
*/
|
||||
iterator erase(iterator it) {
|
||||
return _items.erase(it);
|
||||
}
|
||||
|
||||
iterator erase(iterator first, iterator last) {
|
||||
return _items.erase(first, last);
|
||||
}
|
||||
|
||||
iterator erase(const Key &theKey) {
|
||||
iterator it = find(theKey);
|
||||
if (it != this->end())
|
||||
return erase(it);
|
||||
return it;
|
||||
}
|
||||
|
||||
Pair<iterator, bool> insert(const value_type &val) {
|
||||
iterator it = _items.lowerBound(val.first);
|
||||
if (it == this->end() || !compareEqual(it->first, val.first))
|
||||
return {_items.insert(val), true};
|
||||
return {it, false};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the map
|
||||
*/
|
||||
size_t size() const {
|
||||
return _items.size();
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return _items.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of elements with a matching key
|
||||
*/
|
||||
size_t count(const Key &key) {
|
||||
int count_ = 0;
|
||||
for (iterator it = this->begin(); it != this->end(); ++it) {
|
||||
if (compareEqual(it->first, key))
|
||||
++count_;
|
||||
}
|
||||
return count_;
|
||||
}
|
||||
|
||||
private:
|
||||
bool compareEqual(const Key &a, const Key &b) {
|
||||
return !_comp(a, b) && !_comp(b, a);
|
||||
}
|
||||
|
||||
TreeT _items;
|
||||
CompFunc _comp;
|
||||
};
|
||||
|
||||
} // End of namespace Common
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user