compiles now I think and seems to work but haven't tested extensively
This commit is contained in:
parent
22bfd729e4
commit
b5b03e5fbe
1 changed files with 38 additions and 15 deletions
51
Map.hpp
51
Map.hpp
|
@ -4,11 +4,9 @@
|
|||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
// everything is super interconnected so some forward declarations are needed at
|
||||
// various points
|
||||
|
@ -32,11 +30,12 @@ Direction operator!(Direction dir) {
|
|||
}
|
||||
template <typename Key_T, typename Mapped_T> struct BookKeeping {
|
||||
using Self = BookKeeping<Key_T, Mapped_T>;
|
||||
using ValueType = std::pair<const Key_T, Mapped_T>;
|
||||
using ValueType = std::pair<Key_T, Mapped_T>;
|
||||
using Ptr = typename std::vector<Self>::iterator;
|
||||
friend class Map<Key_T, Mapped_T>;
|
||||
Map<Key_T, Mapped_T> &container;
|
||||
ValueType value;
|
||||
typename std::list<Self>::iterator self;
|
||||
Ptr self;
|
||||
Color color;
|
||||
// nullptr indicates empty
|
||||
Self *parent;
|
||||
|
@ -45,6 +44,26 @@ template <typename Key_T, typename Mapped_T> struct BookKeeping {
|
|||
Self *prev;
|
||||
Self *next;
|
||||
BookKeeping(Map<Key_T, Mapped_T> &container) : container{container} {}
|
||||
BookKeeping(BookKeeping const &rhs)
|
||||
: container{rhs.container}, value{rhs.value}, self{rhs.self},
|
||||
color{rhs.color}, parent{rhs.parent}, left{rhs.left}, right{rhs.right},
|
||||
prev{rhs.prev}, next{rhs.next} {}
|
||||
// if pointing to different containers throws
|
||||
BookKeeping &operator=(BookKeeping const &rhs) {
|
||||
if (&this->container != &rhs.container) {
|
||||
throw std::invalid_argument{"can only reassign Bookkeeping "
|
||||
"values/iterators from the same map object"};
|
||||
}
|
||||
this->value = rhs.value;
|
||||
this->self = rhs.self;
|
||||
this->color = rhs.color;
|
||||
this->parent = rhs.parent;
|
||||
this->left = rhs.left;
|
||||
this->right = rhs.right;
|
||||
this->prev = rhs.prev;
|
||||
this->next = rhs.next;
|
||||
return *this;
|
||||
}
|
||||
// reference to a pointer because the alternatives were worse
|
||||
inline Self *&child(Direction dir) {
|
||||
switch (dir) {
|
||||
|
@ -54,6 +73,8 @@ template <typename Key_T, typename Mapped_T> struct BookKeeping {
|
|||
case Direction::Right:
|
||||
return right;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
// this is root/P for this method
|
||||
|
@ -87,7 +108,7 @@ template <typename Key_T, typename Mapped_T> struct BookKeeping {
|
|||
G->left = S;
|
||||
}
|
||||
} else {
|
||||
T->root = S;
|
||||
T.root = S;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -95,7 +116,7 @@ template <typename Key_T, typename Mapped_T> struct BookKeeping {
|
|||
// https://en.wikipedia.org/wiki/Red%E2%80%93black_tree
|
||||
template <typename Key_T, typename Mapped_T> class Map {
|
||||
private:
|
||||
using ValueType = std::pair<const Key_T, Mapped_T>;
|
||||
using ValueType = std::pair<Key_T, Mapped_T>;
|
||||
using Node = BookKeeping<Key_T, Mapped_T>;
|
||||
using Map_T = Map<Key_T, Mapped_T>;
|
||||
|
||||
|
@ -259,7 +280,7 @@ private:
|
|||
Node *root;
|
||||
Node *min;
|
||||
Node *max;
|
||||
std::list<Node> nodes;
|
||||
std::vector<Node> nodes;
|
||||
|
||||
public:
|
||||
Map() : root{nullptr}, min{nullptr}, max{nullptr}, nodes{} {}
|
||||
|
@ -295,8 +316,12 @@ public:
|
|||
// it here
|
||||
auto [parent, dir] = this->locate_slot(key);
|
||||
if (parent == nullptr) {
|
||||
if (this->root->value.first == key) {
|
||||
return Iterator{root};
|
||||
} else {
|
||||
return this->end();
|
||||
}
|
||||
}
|
||||
if (parent->child(dir) == nullptr) {
|
||||
return this->end();
|
||||
}
|
||||
|
@ -449,13 +474,14 @@ public:
|
|||
// an iterator pointing to the element with the same key, and false.
|
||||
std::pair<Iterator, bool> insert(const ValueType &val) {
|
||||
auto [parent, dir] = locate_slot(val.first);
|
||||
bool ret = parent->child(dir) == nullptr;
|
||||
bool ret = parent == nullptr || parent->child(dir) == nullptr;
|
||||
if (!ret) {
|
||||
return std::make_pair(Iterator{parent->child(dir)}, ret);
|
||||
}
|
||||
Node to_insert{*this};
|
||||
to_insert.value = val;
|
||||
this->nodes.push_back(std::move(to_insert));
|
||||
this->nodes.back().self = (--this->nodes.end());
|
||||
insert_helper(&nodes.back(), parent, dir);
|
||||
|
||||
if (min == nullptr || val.first < min->value.first) {
|
||||
|
@ -465,7 +491,7 @@ public:
|
|||
max = &nodes.back();
|
||||
}
|
||||
|
||||
return std::make_pair(Iterator{&nodes.back()}, ret);
|
||||
return std::make_pair(Iterator(&nodes.back()), ret);
|
||||
}
|
||||
template <typename IT_T> void insert(IT_T range_beg, IT_T range_end) {
|
||||
std::for_each(range_beg, range_end,
|
||||
|
@ -562,7 +588,6 @@ private:
|
|||
public:
|
||||
// TODO: check that the way of reconnecting next and prev works
|
||||
void erase(Iterator pos) {
|
||||
auto &container = pos.ref->container;
|
||||
// simple cases
|
||||
Node *ref = pos.ref;
|
||||
// 2 children
|
||||
|
@ -593,15 +618,13 @@ public:
|
|||
// no children and root
|
||||
else if (ref->left == nullptr && ref->right == nullptr) {
|
||||
this->root = nullptr;
|
||||
this->nodes.erase(ref->value);
|
||||
}
|
||||
// no children and red
|
||||
else if (ref->left == nodes.end() && ref->right == nodes.end()) {
|
||||
else if (ref->left == nullptr && ref->right == nullptr) {
|
||||
Node *next = ref->next;
|
||||
Node *prev = ref->prev;
|
||||
prev->next = next;
|
||||
next->prev = prev;
|
||||
this->nodes.erase(ref->value);
|
||||
}
|
||||
// complicated case of black node with no kids
|
||||
else {
|
||||
|
|
Loading…
Reference in a new issue