From ae0b45df73360da4e7e4c7388529d829f38ace6f Mon Sep 17 00:00:00 2001 From: Pagwin Date: Mon, 25 Nov 2024 22:43:48 -0500 Subject: [PATCH] Fixed issues and setup a makefile for submission --- Makefile | 17 +++++++ Map.hpp | 153 ++++++++++++++++++++++++++++++------------------------- 2 files changed, 100 insertions(+), 70 deletions(-) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..342adce --- /dev/null +++ b/Makefile @@ -0,0 +1,17 @@ +.PHONY: all +all: minimal morse perf test test-kec + +minimal: Map.hpp minimal.cpp + g++ minimal.cpp -o minimal + +morse: Map.hpp morseex.cpp + g++ morseex.cpp -o morse + +perf: Map.hpp test-scaling.cpp + g++ test-scaling.cpp -o perf + +test: Map.hpp test.cpp + g++ test.cpp -o test + +test-kec: Map.hpp test-kec.cpp + g++ test-kec.cpp -o test-kec diff --git a/Map.hpp b/Map.hpp index 4db34ea..78eca8b 100644 --- a/Map.hpp +++ b/Map.hpp @@ -5,12 +5,15 @@ // #define NDEBUG #include #include -#include #include #include namespace cs440 { // universal type defs here namespace { +// technically having this stuff here instead of in a C++ file is wasteful but +// 1) I'm lazy +// 2) idk how to make the Color enum value an implementation detail which the +// template can use but external code can't other than this enum class Direction { Left, Right }; Direction operator!(Direction dir) { switch (dir) { @@ -278,30 +281,28 @@ template class Map { // cannot rotate nullptr assert(this != nullptr); - // we can't be root for this rotate operation assert(this->parent != nullptr); - // if we're missing the child on the opposite direction this is an invalid // rotation assert(this->child(!dir)); + Direction m_dir = this->parent->which_child(this); // gotta pull outselves out of parent to avoid accidentally overwriting // outselves - std::unique_ptr self = - this->parent->uchild(this->parent->which_child(this)); + std::unique_ptr self = this->parent->uchild(m_dir); // make sure this is actually us assert(self.get() == this); // make our former position the position of the relevant child - this->parent->set_child(!dir, this->uchild(!dir)); + this->parent->set_child(m_dir, this->uchild(!dir)); // steal our former child's child - this->set_child(!dir, this->parent->child(!dir)->uchild(dir)); + this->set_child(!dir, this->parent->child(m_dir)->uchild(dir)); // make ourselves our former child's child - this->parent->child(!dir)->set_child(dir, std::move(self)); + this->parent->child(m_dir)->set_child(dir, std::move(self)); } // Referencing // https://en.wikipedia.org/wiki/Red%E2%80%93black_tree#Notes_to_the_insert_diagrams @@ -318,6 +319,7 @@ template class Map { return; } + dir = parent->which_child(self); // if this is violated it's a bug assert(parent->child(dir) == self); @@ -334,6 +336,7 @@ template class Map { return; } + dir = parent->which_child(self); // table showing transforms on wikipedia doesn't have this so if it // happens it's probably a bug assert(grandparent->color == Color::Black); @@ -343,7 +346,7 @@ template class Map { if (parent->which_child(self) != grandparent->which_child(parent)) { // we're an inner child // case 5 - parent->rotate(dir); + parent->rotate(!dir); self = parent; parent = self->parent; } @@ -352,10 +355,10 @@ template class Map { // recolor first so we aren't recoloring a dropped reference or smth parent->color = Color::Black; grandparent->color = Color::Red; - if (grandparent->parent == nullptr) { - map->rotate_root(!dir); + if (grandparent->parent) { + grandparent->rotate(!grandparent->which_child(parent)); } else { - grandparent->rotate(!dir); + map->rotate_root(!grandparent->which_child(parent)); } return; } @@ -370,7 +373,7 @@ template class Map { }; // data needed for implementation - std::optional root; + std::unique_ptr root; std::size_t _size; Node *min; Node *max; @@ -526,12 +529,21 @@ public: } const ValueType &operator*() const { return this->underlying.operator*(); } const ValueType *operator->() const { return &this->operator*(); } + friend bool operator==(const ReverseIterator &lhs, + const ReverseIterator &rhs) { + return lhs.underlying == rhs.underlying; + } + friend bool operator!=(const ReverseIterator &lhs, + const ReverseIterator &rhs) { + return !(lhs == rhs); + } }; - Map() : root{}, _size{0} {} - Map(const Map &rhs) : root{rhs.root}, _size{rhs._size} { - this->min = &this->root.value(); - this->max = &this->root.value(); + Map() : root{}, _size{0}, min{nullptr}, max{nullptr} {} + Map(const Map &rhs) + : root{std::make_unique(*rhs.root)}, _size{rhs._size} { + this->min = this->root.get(); + this->max = this->root.get(); while (min->left) { min = min->left.get(); } @@ -540,8 +552,8 @@ public: } } Map(Map &&rhs) : root{std::move(rhs.root)}, _size{rhs._size} { - this->min = &this->root.value(); - this->max = &this->root.value(); + this->min = this->root.get(); + this->max = this->root.get(); while (min->left) { min = min->left.get(); } @@ -550,10 +562,10 @@ public: } } Map &operator=(const Map &rhs) { - this->root = rhs.root; + this->root = std::make_unique(*rhs.root); this->_size = rhs._size; - this->min = &this->root.value(); - this->max = &this->root.value(); + this->min = this->root.get(); + this->max = this->root.get(); while (min->left) { min = min->left.get(); } @@ -565,8 +577,8 @@ public: Map &operator=(Map &&rhs) { this->root = std::move(rhs.root); this->_size = rhs._size; - this->min = &this->root.value(); - this->max = &this->root.value(); + this->min = this->root.get(); + this->max = this->root.get(); while (min->left) { min = min->left.get(); } @@ -578,27 +590,24 @@ public: Map(std::initializer_list> items) : Map{} { this->insert(items.begin(), items.end()); } - void check() { - assert(!this->root || this->root.value().color == Color::Black); - } std::size_t size() const { return this->_size; } bool empty() const { return this->size() == 0; } private: // private helpers void rotate_root(Direction dir) { - assert(root.has_value()); + assert(root); - std::unique_ptr new_root = root.value().uchild(!dir); + std::unique_ptr new_root = root->uchild(!dir); // can't make null the new root assert(new_root); - std::unique_ptr old_root = - std::make_unique(std::move(root.value())); + std::unique_ptr old_root = std::move(root); - root.value() = std::move(*new_root.release()); + root = std::move(new_root); + root->parent = nullptr; - old_root->set_child(!dir, root.value().uchild(dir)); + old_root->set_child(!dir, root->uchild(dir)); if (old_root->left) { old_root->left->parent = old_root.get(); @@ -606,43 +615,44 @@ private: if (old_root->right) { old_root->right->parent = old_root.get(); } - if (old_root->next) { - old_root->next->prev = old_root.get(); - } - if (old_root->prev) { - old_root->prev->next = old_root.get(); - } + // if (old_root->next) { + // old_root->next->prev = old_root.get(); + // } + // if (old_root->prev) { + // old_root->prev->next = old_root.get(); + // } - root.value().set_child(dir, std::move(old_root)); - root.value().child(dir)->restore_ordering(); + root->set_child(dir, std::move(old_root)); + root->child(dir)->restore_ordering(); - if (root.value().left) { - root.value().left->parent = &root.value(); - if (min == &root.value()) { - min = root.value().left.get(); + if (root->left) { + root->left->parent = root.get(); + if (min == root.get()) { + min = root->left.get(); } } - if (root.value().right) { - root.value().right->parent = &root.value(); - if (max == &root.value()) { - max = root.value().right.get(); + if (root->right) { + root->right->parent = root.get(); + if (max == root.get()) { + max = root->right.get(); } } } + template std::pair locate(const Key_T &key) const { Node const *ret_parent; Direction ret_dir; // map is empty - if (!this->root.has_value()) { + if (!this->root) { return std::make_pair(nullptr, ret_dir); } // value is in root - if (this->root.value().val->first == key) { + if (this->root->val->first == key) { return std::make_pair(nullptr, ret_dir); } - ret_parent = &this->root.value(); + ret_parent = this->root.get(); if (key < ret_parent->val->first) { ret_dir = Direction::Left; } else { @@ -690,7 +700,7 @@ private: // bookkeeping redcheck(sibling_color) { // case 3 - if (parent->parent != nullptr) { + if (parent->parent) { parent->rotate(dir); } else { parent->map->rotate_root(dir); @@ -727,7 +737,7 @@ private: assert(parent); assert(sibling); assert(distant); - if (parent->parent != nullptr) { + if (parent->parent) { parent->rotate(dir); } else { parent->map->rotate_root(dir); @@ -787,7 +797,7 @@ private: } // no children and root else if (erasing->parent == nullptr) { - erasing->map->root = std::nullopt; + erasing->map->root = nullptr; } // no children and red else if (erasing->color == Color::Red) { @@ -805,9 +815,9 @@ public: Iterator find(const Key_T &key) { auto [parent, dir] = locate(key); if (parent == nullptr) { - if (this->root.has_value()) { - if (this->root.value().val->first == key) { - return Iterator{&this->root.value()}; + if (this->root) { + if (this->root->val->first == key) { + return Iterator{this->root.get()}; } } return this->end(); @@ -820,9 +830,9 @@ public: ConstIterator find(const Key_T &key) const { auto [parent, dir] = locate(key); if (parent == nullptr) { - if (this->root.has_value()) { - if (this->root.value().val->first == key) { - return Iterator{const_cast(&this->root.value())}; + if (this->root) { + if (this->root->val->first == key) { + return Iterator{const_cast(this->root.get())}; } } return this->end(); @@ -840,15 +850,15 @@ public: auto [parent, dir] = locate(key); // located root node if (parent == nullptr) { - if (this->root.has_value()) { - return std::make_pair(Iterator{&root.value()}, false); + if (this->root) { + return std::make_pair(Iterator{root.get()}, false); } else { - this->root = Node{val, this}; - this->root.value().color = Color::Black; - this->min = &this->root.value(); - this->max = &this->root.value(); + this->root = std::make_unique(Node{val, this}); + this->root->color = Color::Black; + this->min = this->root.get(); + this->max = this->root.get(); this->_size++; - return std::make_pair(Iterator{&root.value()}, true); + return std::make_pair(Iterator{root.get()}, true); } } @@ -865,7 +875,10 @@ public: ->set_child(dir, std::make_unique(Node{val, m})) .get(); new_node->restore_red_black_insert(dir); - + // if the new_node_ptr isn't valid anymore then it has to be root + if (new_node->valid != 0x13371337) { + new_node = this->root.get(); + } new_node->restore_ordering(); if (this->min == parent && dir == Direction::Left) { this->min = new_node; @@ -916,7 +929,7 @@ public: // misc that can be implemented with the above or trivially void clear() { - this->root = std::move(std::nullopt); + this->root = std::move(nullptr); this->_size = 0; } Mapped_T &at(const Key_T &key) {