compiles now I think and seems to work but haven't tested extensively

This commit is contained in:
Pagwin 2024-11-22 14:57:43 -05:00
parent 22bfd729e4
commit b5b03e5fbe
No known key found for this signature in database
GPG key ID: 81137023740CA260

51
Map.hpp
View file

@ -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,8 +316,12 @@ 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) {
if (this->root->value.first == key) {
return Iterator{root};
} else {
return this->end(); 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 {