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