suffering from memory corruption issues, not sure where the issue is

This commit is contained in:
Pagwin 2024-11-23 23:17:05 -05:00
parent 62cdce3f2e
commit c48eff8fc7
No known key found for this signature in database
GPG key ID: 81137023740CA260
2 changed files with 172 additions and 58 deletions

176
Map.hpp
View file

@ -1,6 +1,8 @@
#ifndef _POWELL_CS440
#define _POWELL_CS440
#include <algorithm>
// uncomment on submission/performance test
// #define NDEBUG
#include <cassert>
#include <iostream>
#include <memory>
@ -20,9 +22,6 @@ Direction operator!(Direction dir) {
assert(false);
}
}
int x5 = 5;
int x6 = 6;
int x7 = 7;
enum class Color { Red, Black };
} // namespace
template <typename Key_T, typename Mapped_T> class Map {
@ -31,6 +30,7 @@ template <typename Key_T, typename Mapped_T> class Map {
using internal_ValueType = std::pair<Key_T, Mapped_T>;
struct Node {
int valid = 0x13371337;
Node *parent;
internal_ValueType val;
std::unique_ptr<Node> left;
@ -58,6 +58,10 @@ template <typename Key_T, typename Mapped_T> class Map {
: parent{nullptr}, val{std::move(rhs.val)}, left{std::move(rhs.left)},
right{std::move(rhs.right)}, color{rhs.color}, prev{nullptr},
next{nullptr}, map{rhs.map} {
if (rhs.valid != 0x13371337) {
std::cerr << "(" << rhs.val.first << ")" << std::endl;
}
rhs.valid = 0;
if (this->left) {
this->left->parent = this;
}
@ -171,9 +175,14 @@ template <typename Key_T, typename Mapped_T> class Map {
// intuitively should be correct but might need to do restore ordering on
// both instead
if (dropping->prev != nullptr) {
dropping->prev->next = dropping->next;
}
if (dropping->next != nullptr) {
dropping->next->prev = dropping->prev;
}
}
void restore_ordering() {
this->prev = this->calc_pred();
this->next = this->calc_succ();
@ -246,7 +255,6 @@ template <typename Key_T, typename Mapped_T> class Map {
// make ourselves our former child's child
this->parent->child(!dir)->set_child(dir, std::move(self));
}
// TODO:
// Referencing
// https://en.wikipedia.org/wiki/Red%E2%80%93black_tree#Notes_to_the_insert_diagrams
void restore_red_black_insert(Direction dir) {
@ -310,8 +318,6 @@ template <typename Key_T, typename Mapped_T> class Map {
self = grandparent;
}
}
// TODO:
void restore_red_black_erase() {}
};
// data needed for implementation
@ -332,6 +338,15 @@ public:
public:
friend Map;
Iterator() = delete;
void check() {
assert(underlying->val.first < 200);
if (underlying->prev != nullptr) {
assert(underlying->prev->val.first < 200);
}
if (underlying->next != nullptr) {
assert(underlying->next->val.first < 200);
}
}
};
Map() : root{}, _size{0} {}
Map(const Map &rhs) : root{rhs.root}, _size{rhs._size} {}
@ -362,7 +377,7 @@ private:
root.value() = std::move(*new_root);
old_root->set_child(!dir, std::move(root.value().uchild(dir)));
old_root->set_child(!dir, root.value().uchild(dir));
root.value().set_child(dir, std::move(old_root));
}
template <bool trace = false>
@ -420,6 +435,131 @@ private:
}
return std::make_pair(ret_parent, ret_dir);
}
void hard_erase(Node *n) {
assert(n->parent);
Node *parent = n->parent;
Direction dir = parent->which_child(n);
parent->erase_child(n);
goto skip;
while (true) {
parent = n->parent;
if (parent == nullptr) {
// we're at root we're done (case 1)
return;
}
dir = parent->which_child(n);
skip:
Color par_color = parent->color;
Node *sibling = parent->child(!dir);
Color sibling_color = sibling ? sibling->color : Color::Black;
Node *close = sibling ? sibling->child(dir) : nullptr;
Node *distant = sibling ? sibling->child(!dir) : nullptr;
Color close_color = close ? close->color : Color::Black;
Color distant_color = distant ? distant->color : Color::Black;
#define redcheck(v) if ((v) == Color::Red)
// it kinda sucks but I think that goto is genuinely the best solution
// here, making methods for cases 4,5 and 6 is a lot of unneeded
// bookkeeping
redcheck(sibling_color) {
// case 3
if (parent->parent != nullptr) {
parent->rotate(dir);
} else {
parent->map->rotate_root(dir);
}
parent->color = Color::Red;
sibling->color = Color::Black;
sibling = close;
distant = sibling->child(!dir);
if (distant != nullptr && distant->color == Color::Red) {
goto case_6;
}
close = sibling->child(dir);
if (close != nullptr && close->color == Color::Red) {
goto case_5;
}
goto case_4;
}
else redcheck(close_color) {
// case 5
case_5:
assert(sibling);
assert(close);
sibling->rotate(!dir);
sibling->color = Color::Red;
close->color = Color::Black;
distant = sibling;
sibling = close;
goto case_6;
}
else redcheck(distant_color) {
// case 6
case_6:
assert(parent);
assert(sibling);
assert(distant);
if (parent->parent != nullptr) {
parent->rotate(dir);
} else {
parent->map->rotate_root(dir);
}
Color tmp = parent->color;
sibling->color = tmp;
parent->color = Color::Black;
distant->color = Color::Black;
return;
}
else redcheck(par_color) {
// case 4
case_4:
assert(sibling);
sibling->color = Color::Red;
parent->color = Color::Black;
return;
}
else {
// case 2
assert(sibling);
sibling->color = Color::Red;
n = parent;
continue;
}
}
}
bool core_erase(Node *erasing) {
// 2 children
if (erasing->left && erasing->right) {
Node *succ = erasing->next;
erasing->val = succ->val;
this->core_erase(succ);
}
// 1 child
else if (erasing->left) {
*erasing = std::move(*erasing->left);
return true;
} else if (erasing->right) {
*erasing = std::move(*erasing->right);
return true;
}
// no children and root
else if (!erasing->parent) {
erasing->map->root = std::nullopt;
}
// no children and red
else if (erasing->color == Color::Red) {
erasing->parent->erase_child(erasing);
}
// no children and black
else {
hard_erase(erasing);
}
return false;
}
public:
// baseline find using locate
@ -483,9 +623,25 @@ public:
return std::make_pair(Iterator{new_node}, true);
}
void erase(Iterator pos) {
Node *p = pos.underlying->parent;
p->erase_child(pos.underlying);
p->restore_red_black_erase();
Node *before = pos.underlying->prev;
Node *after = pos.underlying->next;
if (core_erase(pos.underlying)) {
pos.underlying->restore_ordering();
} else {
if (before != nullptr) {
before->next = before->calc_succ();
if (before->next != nullptr) {
before->next->prev = before;
}
}
if (after != nullptr) {
after->prev = after->calc_pred();
if (after->prev != nullptr) {
after->prev->next = after;
}
}
}
}
// baseline iterator creation

50
t.cpp
View file

@ -3,9 +3,6 @@
template class cs440::Map<int, int>;
int main(void) {
cs440::Map<int, int> a;
int x5 = 5;
int x6 = 6;
int x7 = 7;
a.insert({1, 1});
a.insert({2, 2});
a.insert({3, 3});
@ -16,49 +13,10 @@ int main(void) {
a.insert({8, 8});
a.insert({9, 9});
a.insert({10, 10});
a.insert({11, 11});
a.insert({12, 12});
a.insert({13, 13});
a.insert({14, 14});
a.insert({15, 15});
a.insert({16, 16});
a.insert({17, 17});
a.insert({18, 18});
a.insert({19, 19});
a.insert({20, 20});
a.insert({21, 21});
a.insert({22, 22});
a.insert({23, 23});
a.insert({24, 24});
a.insert({25, 25});
a.insert({26, 26});
a.insert({27, 27});
a.insert({28, 28});
a.insert({29, 29});
a.insert({30, 30});
a.insert({31, 31});
a.insert({32, 32});
a.insert({33, 33});
a.insert({34, 34});
a.insert({35, 35});
a.insert({36, 36});
a.insert({37, 37});
a.insert({38, 38});
a.insert({39, 39});
a.insert({40, 40});
a.insert({41, 41});
a.insert({42, 42});
a.insert({43, 43});
a.insert({44, 44});
a.insert({45, 45});
a.insert({46, 46});
a.insert({47, 47});
a.insert({48, 48});
a.insert({49, 49});
a.insert({50, 50});
for (std::size_t i = 1; i <= 50; i++) {
std::cout << i << "\t";
a.find_trace(i);
for (std::size_t i = 1; i <= 10; i++) {
// a.find(i).check();
std::cout << i << std::endl;
a.erase(a.find(i));
}
return 0;
}