diff --git a/Map.hpp b/Map.hpp index 5ac104f..aa7f83b 100644 --- a/Map.hpp +++ b/Map.hpp @@ -4,7 +4,6 @@ // uncomment on submission/performance test // #define NDEBUG #include -#include #include #include #include @@ -32,8 +31,8 @@ template class Map { struct Node { int valid = 0x13371337; - Node *parent; - internal_ValueType val; + Node *parent = nullptr; + std::unique_ptr val; std::unique_ptr left; std::unique_ptr right; Color color; @@ -41,13 +40,14 @@ template class Map { Node *next; Map *map; Node(internal_ValueType val, Map *map) - : parent{nullptr}, val{val}, left{}, right{}, color{Color::Red}, - prev{nullptr}, next{nullptr}, map{map} {} + : parent{nullptr}, val{new internal_ValueType{val}}, left{}, right{}, + color{Color::Red}, prev{nullptr}, next{nullptr}, map{map} {} Node(const Node &rhs) - : parent{nullptr}, val{rhs.val}, - left{std::make_unique(*rhs.left)}, - right{std::make_unique(*rhs.right)}, color{rhs.color}, - prev{nullptr}, next{nullptr}, map{rhs.map} { + : parent{nullptr}, + val{rhs.val ? new internal_ValueType{*rhs.val} : nullptr}, + left{rhs.left ? std::make_unique(*rhs.left) : nullptr}, + right{rhs.right ? std::make_unique(*rhs.right) : nullptr}, + color{rhs.color}, prev{nullptr}, next{nullptr}, map{rhs.map} { this->valid = 0x13371337; if (this->left) { @@ -64,11 +64,7 @@ template 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} { - // TODO: remove on finish - if (rhs.valid != 0x13371337) { - std::cerr << "(" << rhs.val.first << ")" << std::endl; - } rhs.valid = 0; this->valid = 0x13371337; @@ -88,9 +84,12 @@ template class Map { // to a rotation where parent can get wonky // this->parent - this->val = rhs.val; - this->left = std::make_unique(*rhs.left); - this->right = std::make_unique(*rhs.right); + this->val = + rhs.val ? std::unique_ptr{new internal_ValueType{ + *rhs.val}} + : nullptr; + this->left = rhs.left ? std::make_unique(*rhs.left) : nullptr; + this->right = rhs.right ? std::make_unique(*rhs.right) : nullptr; this->color = rhs.color; this->valid = 0x13371337; @@ -110,7 +109,7 @@ template class Map { // retain parent as is, common case is the copy or move is happening due // to a rotation where parent can get wonky // this->parent - this->val = rhs.val; + this->val = std::move(rhs.val); this->left = std::move(rhs.left); this->right = std::move(rhs.right); this->color = rhs.color; @@ -532,8 +531,26 @@ public: }; Map() : root{}, _size{0} {} - Map(const Map &rhs) : root{rhs.root}, _size{rhs._size} {} - Map(Map &&rhs) : root{std::move(rhs.root)}, _size{rhs._size} {} + Map(const Map &rhs) : root{rhs.root}, _size{rhs._size} { + this->min = &this->root.value(); + this->max = &this->root.value(); + while (min->left) { + min = min->left.get(); + } + while (min->right) { + min = min->left.get(); + } + } + Map(Map &&rhs) : root{std::move(rhs.root)}, _size{rhs._size} { + this->min = &this->root.value(); + this->max = &this->root.value(); + while (min->left) { + min = min->left.get(); + } + while (min->right) { + min = min->left.get(); + } + } Map &operator=(const Map &rhs) { this->root = rhs.root; this->_size = rhs._size; @@ -550,8 +567,8 @@ public: void check() { assert(!this->root || this->root.value().color == Color::Black); } - std::size_t size() { return this->_size; } - bool empty() { return this->size() == 0; } + std::size_t size() const { return this->_size; } + bool empty() const { return this->size() == 0; } private: // private helpers @@ -604,53 +621,28 @@ private: Direction ret_dir; // map is empty if (!this->root.has_value()) { - if constexpr (trace) { - std::cerr << "(map empty)" << std::endl; - } return std::make_pair(nullptr, ret_dir); } - if constexpr (trace) { - std::cerr << "root"; - } // value is in root - if (this->root.value().val.first == key) { - - if constexpr (trace) { - std::cerr << "->found" << std::endl; - } + if (this->root.value().val->first == key) { return std::make_pair(nullptr, ret_dir); } ret_parent = &this->root.value(); - if (key < ret_parent->val.first) { - if constexpr (trace) { - std::cerr << "->left"; - } + if (key < ret_parent->val->first) { ret_dir = Direction::Left; } else { - if constexpr (trace) { - std::cerr << "->right"; - } ret_dir = Direction::Right; } while (ret_parent->child(ret_dir) && - ret_parent->child(ret_dir)->val.first != key) { + !(ret_parent->child(ret_dir)->val->first == key)) { ret_parent = ret_parent->child(ret_dir); - if (key < ret_parent->val.first) { - if constexpr (trace) { - std::cerr << "->left"; - } + if (key < ret_parent->val->first) { ret_dir = Direction::Left; } else { - if constexpr (trace) { - std::cerr << "->right"; - } ret_dir = Direction::Right; } } - if constexpr (trace) { - std::cerr << "->found" << std::endl; - } return std::make_pair(ret_parent, ret_dir); } void hard_erase(Node *n) { @@ -754,7 +746,7 @@ private: // 2 children if (erasing->left && erasing->right) { Node *succ = erasing->next; - erasing->val = succ->val; + erasing->val = std::move(succ->val); this->core_erase(succ); } // 1 child @@ -800,7 +792,7 @@ public: auto [parent, dir] = locate(key); if (parent == nullptr) { if (this->root.has_value()) { - if (this->root.value().val.first == key) { + if (this->root.value().val->first == key) { return Iterator{&this->root.value()}; } } @@ -815,7 +807,7 @@ public: auto [parent, dir] = locate(key); if (parent == nullptr) { if (this->root.has_value()) { - if (this->root.value().val.first == key) { + if (this->root.value().val->first == key) { return Iterator{const_cast(&this->root.value())}; } } @@ -881,7 +873,7 @@ public: if (core_erase(pos.underlying)) { pos.underlying->restore_ordering(); } else { - if (before != nullptr) { + if (before != nullptr && before->valid == 0x13371337) { before->next = before->calc_succ(); if (before->next != nullptr) { before->next->prev = before; @@ -889,7 +881,7 @@ public: } else { this->min = after; } - if (after != nullptr) { + if (after != nullptr && after->valid == 0x13371337) { after->prev = after->calc_pred(); if (after->prev != nullptr) { after->prev->next = after; @@ -925,7 +917,7 @@ public: if (ret == this->end()) { throw std::out_of_range{"key not in map"}; } - return (*ret).first; + return (*ret).second; } Mapped_T &operator[](const Key_T &key) { this->insert({key, {}}); @@ -939,7 +931,6 @@ public: } } void erase(const Key_T &key) { this->erase(this->find(key)); } - // TODO: friend bool operator==(const Map &lhs, const Map &rhs) { if (lhs.size() != rhs.size()) { return false; diff --git a/minimal.cpp b/minimal.cpp index ef7ab88..8b28a68 100644 --- a/minimal.cpp +++ b/minimal.cpp @@ -4,119 +4,116 @@ // basically an int wrapper class MyKeyType { - private: - int val; +private: + int val; - public: - //not default constructable, not copy assignable, not move assignable - MyKeyType() = delete; - MyKeyType& operator=(const MyKeyType&) = delete; - MyKeyType& operator=(MyKeyType&&) = delete; +public: + // not default constructable, not copy assignable, not move assignable + MyKeyType() = delete; + MyKeyType &operator=(const MyKeyType &) = delete; + MyKeyType &operator=(MyKeyType &&) = delete; - // copy constructable and move assignable - MyKeyType(MyKeyType&&) = default; - MyKeyType(const MyKeyType&) = default; - ~MyKeyType() = default; + // copy constructable and move assignable + MyKeyType(MyKeyType &&) = default; + MyKeyType(const MyKeyType &) = default; + ~MyKeyType() = default; - MyKeyType(int i) : val(i) { } + MyKeyType(int i) : val(i) {} - bool operator<(const MyKeyType& other) const { - return this->val < other.val; - } + bool operator<(const MyKeyType &other) const { return this->val < other.val; } - bool operator==(const MyKeyType &other) const { - return this->val == other.val; - } + bool operator==(const MyKeyType &other) const { + return this->val == other.val; + } }; // same as keytype except no operator< class MyValueType { - private: - int val; +private: + int val; - public: - //not default constructable, not copy assignable, not move assignable - MyValueType() = delete; - MyValueType& operator=(const MyValueType&) = delete; - MyValueType& operator=(MyValueType&&) = delete; +public: + // not default constructable, not copy assignable, not move assignable + MyValueType() = delete; + MyValueType &operator=(const MyValueType &) = delete; + MyValueType &operator=(MyValueType &&) = delete; - // copy constructable and move assignable - MyValueType(MyValueType&&) = default; - MyValueType(const MyValueType&) = default; - ~MyValueType() = default; + // copy constructable and move assignable + MyValueType(MyValueType &&) = default; + MyValueType(const MyValueType &) = default; + ~MyValueType() = default; - MyValueType(int i) : val(i) { } + MyValueType(int i) : val(i) {} - bool operator==(const MyValueType &other) const { - return this->val == other.val; - } + bool operator==(const MyValueType &other) const { + return this->val == other.val; + } }; class MyDefaultConstructible { - friend bool operator<(const MyDefaultConstructible &o1, const MyDefaultConstructible &o2) { - return o1.val < o2.val; - } + friend bool operator<(const MyDefaultConstructible &o1, + const MyDefaultConstructible &o2) { + return o1.val < o2.val; + } - private: - int val = 0; +private: + int val = 0; - public: - // not copy assignable, not move assignable - MyDefaultConstructible& operator=(const MyDefaultConstructible&) = delete; - MyDefaultConstructible& operator=(MyDefaultConstructible&&) = delete; +public: + // not copy assignable, not move assignable + MyDefaultConstructible &operator=(const MyDefaultConstructible &) = delete; + MyDefaultConstructible &operator=(MyDefaultConstructible &&) = delete; - // default constructable, copy constructable and move assignable - MyDefaultConstructible() = default; - MyDefaultConstructible(MyDefaultConstructible&&) = default; - MyDefaultConstructible(const MyDefaultConstructible&) = default; - ~MyDefaultConstructible() = default; + // default constructable, copy constructable and move assignable + MyDefaultConstructible() = default; + MyDefaultConstructible(MyDefaultConstructible &&) = default; + MyDefaultConstructible(const MyDefaultConstructible &) = default; + ~MyDefaultConstructible() = default; - MyDefaultConstructible(int i) : val(i) { } + MyDefaultConstructible(int i) : val(i) {} - bool operator==(const MyDefaultConstructible &other) const { - return this->val == other.val; - } + bool operator==(const MyDefaultConstructible &other) const { + return this->val == other.val; + } }; - class MyAssignable { - private: - int val = 0; +private: + int val = 0; - public: - MyAssignable() = default; - MyAssignable(int i) : val(i) { } - bool operator==(const MyAssignable &other) const { - return this->val == other.val; - } +public: + MyAssignable() = default; + MyAssignable(int i) : val(i) {} + bool operator==(const MyAssignable &other) const { + return this->val == other.val; + } }; -// manual instantiation, instantiates every member function instead of +// manual instantiation, instantiates every member function instead of // just the ones called template class cs440::Map; - int main() { - cs440::Map m{{3, 5}}; - m.insert({{2}, {3}}); - m.insert({{1}, {3}}); - m.insert({{5}, {3}}); - m.insert({{7}, {3}}); - m.at(2); - auto iter = m.find(2); - m.erase(iter); - auto m_copy = m; - assert(m_copy == m); + cs440::Map m{{3, 5}}; + m.insert({{2}, {3}}); + m.insert({{1}, {3}}); + m.insert({{5}, {3}}); + m.insert({{7}, {3}}); + m.at(2); + auto iter = m.find(2); + m.erase(iter); + auto m_copy = m; + assert(m_copy == m); - cs440::Map m2{{8, 9}}; - m2[10]; // should default construct these values - m2[15]; + cs440::Map m2{{8, 9}}; + m2[10]; // should default construct these values + m2[15]; - cs440::Map m3{{6, 7}}; - m3[20] = {5}; // move assign - MyAssignable ma{1}; - m3[10] = ma; //copy assign + cs440::Map m3{{6, 7}}; + m3[20] = {5}; // move assign + MyAssignable ma{1}; + m3[10] = ma; // copy assign - return 0; + return 0; }