did most of the misc stuff just need < and ==

This commit is contained in:
Pagwin 2024-11-24 20:42:13 -05:00
parent 27409cc0b0
commit 09d2323cbf
No known key found for this signature in database
GPG key ID: 81137023740CA260
2 changed files with 275 additions and 48 deletions

293
Map.hpp
View file

@ -7,6 +7,7 @@
#include <iostream> #include <iostream>
#include <memory> #include <memory>
#include <optional> #include <optional>
#include <stdexcept>
#include <utility> #include <utility>
namespace cs440 { namespace cs440 {
// universal type defs here // universal type defs here
@ -47,12 +48,17 @@ template <typename Key_T, typename Mapped_T> class Map {
left{std::make_unique<Node>(*rhs.left)}, left{std::make_unique<Node>(*rhs.left)},
right{std::make_unique<Node>(*rhs.right)}, color{rhs.color}, right{std::make_unique<Node>(*rhs.right)}, color{rhs.color},
prev{nullptr}, next{nullptr}, map{rhs.map} { prev{nullptr}, next{nullptr}, map{rhs.map} {
this->valid = 0x13371337;
if (this->left) { if (this->left) {
this->left->parent = this; this->left->parent = this;
} }
if (this->right) { if (this->right) {
this->right->parent = this; this->right->parent = this;
} }
this->next = rhs.next;
this->prev = rhs.prev;
} }
Node(Node &&rhs) Node(Node &&rhs)
: parent{nullptr}, val{std::move(rhs.val)}, left{std::move(rhs.left)}, : parent{nullptr}, val{std::move(rhs.val)}, left{std::move(rhs.left)},
@ -72,17 +78,22 @@ template <typename Key_T, typename Mapped_T> class Map {
if (this->right) { if (this->right) {
this->right->parent = this; this->right->parent = this;
} }
this->next = rhs.next;
this->prev = rhs.prev;
} }
~Node() {} ~Node() {}
Node &operator=(const Node &rhs) { Node &operator=(const Node &rhs) {
// retain parent as is, common case is the copy or move is happening due // retain parent as is, common case is the copy or move is happening due
// to a rotation where parent can get wonky // to a rotation where parent can get wonky
// this->parent // this->parent
this->val = rhs.val; this->val = rhs.val;
this->left = std::make_unique<Node>(*rhs.left); this->left = std::make_unique<Node>(*rhs.left);
this->right = std::make_unique<Node>(*rhs.right); this->right = std::make_unique<Node>(*rhs.right);
this->color = rhs.color; this->color = rhs.color;
this->valid = 0x13371337; this->valid = 0x13371337;
if (this->left) { if (this->left) {
this->left->parent = this; this->left->parent = this;
this->left->restore_ordering(); this->left->restore_ordering();
@ -91,7 +102,7 @@ template <typename Key_T, typename Mapped_T> class Map {
this->right->parent = this; this->right->parent = this;
this->right->restore_ordering(); this->right->restore_ordering();
} }
this->restore_ordering();
this->map = rhs.map; this->map = rhs.map;
return *this; return *this;
} }
@ -113,6 +124,7 @@ template <typename Key_T, typename Mapped_T> class Map {
this->right->parent = this; this->right->parent = this;
this->right->restore_ordering(); this->right->restore_ordering();
} }
this->restore_ordering();
this->map = rhs.map; this->map = rhs.map;
return *this; return *this;
} }
@ -126,6 +138,16 @@ template <typename Key_T, typename Mapped_T> class Map {
assert(false); assert(false);
} }
} }
Node const *child(Direction dir) const {
switch (dir) {
case Direction::Left:
return this->left.get();
case Direction::Right:
return this->right.get();
default:
assert(false);
}
}
std::unique_ptr<Node> uchild(Direction dir) { std::unique_ptr<Node> uchild(Direction dir) {
switch (dir) { switch (dir) {
case Direction::Left: case Direction::Left:
@ -174,6 +196,8 @@ template <typename Key_T, typename Mapped_T> class Map {
} }
void erase_child(Node *n) { this->erase_child(this->which_child(n)); } void erase_child(Node *n) { this->erase_child(this->which_child(n)); }
void erase_child(Direction dir) { void erase_child(Direction dir) {
bool minmax = this->child(dir) == this->map->min ||
this->child(dir) == this->map->max;
// bringing ownership to this function scope so Deleter gets called at end // bringing ownership to this function scope so Deleter gets called at end
// of function and we can do reordering things // of function and we can do reordering things
std::unique_ptr<Node> dropping; std::unique_ptr<Node> dropping;
@ -197,6 +221,18 @@ template <typename Key_T, typename Mapped_T> class Map {
if (dropping->next != nullptr) { if (dropping->next != nullptr) {
dropping->next->prev = dropping->prev; dropping->next->prev = dropping->prev;
} }
if (minmax) {
switch (dir) {
case Direction::Left:
this->map->min = this;
break;
case Direction::Right:
this->map->max = this;
break;
assert(false);
}
}
} }
void restore_ordering() { void restore_ordering() {
this->prev = this->calc_pred(); this->prev = this->calc_pred();
@ -344,6 +380,8 @@ template <typename Key_T, typename Mapped_T> class Map {
public: public:
friend Node; friend Node;
class ConstIterator;
class ReverseIterator;
// public type definitions // public type definitions
class Iterator { class Iterator {
Node *underlying; Node *underlying;
@ -353,34 +391,146 @@ public:
public: public:
friend Map; friend Map;
friend ConstIterator;
friend ReverseIterator;
Iterator() = delete; Iterator() = delete;
void check() { Iterator(const Iterator &rhs) = default;
Iterator &operator=(const Iterator &) = default;
~Iterator() = default;
// precrement
Iterator &operator++() {
if (this->underlying == nullptr) { if (this->underlying == nullptr) {
return; this->underlying = this->store;
this->store = nullptr;
return *this;
} }
if (this->underlying->parent) { if (this->underlying->next == nullptr) {
switch (this->underlying->parent->which_child(this->underlying)) { this->store = this->underlying;
case Direction::Left:
assert(this->underlying->val.first <
this->underlying->parent->val.first);
break;
case Direction::Right:
assert(this->underlying->val.first >
this->underlying->parent->val.first);
break;
default:
assert(false);
}
} }
if (this->underlying->right) { this->underlying = this->underlying->next;
assert(this->underlying->right->val.first > return *this;
this->underlying->val.first); }
// postcrement
Iterator operator++(int) {
auto copy = *this;
this->operator++();
return copy;
}
// precrement
Iterator &operator--() {
if (this->underlying == nullptr) {
this->underlying = this->store;
this->store = nullptr;
return *this;
} }
if (this->underlying->left) { if (this->underlying->prev == nullptr) {
assert(this->underlying->left->val.first < this->underlying->val.first); this->store = this->underlying;
} }
this->underlying = this->underlying->prev;
return *this;
}
// postcrement
Iterator operator--(int) {
auto copy = *this;
this->operator--();
return copy;
}
ValueType &operator*() const {
ValueType *ret = (ValueType *)(&this->underlying->val);
return *ret;
}
ValueType *operator->() const { return &this->operator*(); }
friend bool operator==(const Iterator &lhs, const Iterator &rhs) {
return lhs.underlying == rhs.underlying;
}
friend bool operator!=(const Iterator &lhs, const Iterator &rhs) {
return !(lhs == rhs);
} }
}; };
class ConstIterator {
Iterator underlying;
public:
friend Map;
ConstIterator() = delete;
ConstIterator(const Iterator &underlying) : underlying{underlying} {}
ConstIterator(const ConstIterator &rhs) = default;
ConstIterator &operator=(const ConstIterator &) = default;
~ConstIterator() = default;
ConstIterator &operator++() {
++underlying;
return *this;
}
ConstIterator operator++(int) {
auto copy = *this;
this->operator++();
return copy;
}
ConstIterator &operator--() {
--underlying;
return *this;
}
ConstIterator operator--(int) {
auto copy = *this;
this->operator--();
return copy;
}
const ValueType &operator*() const { return this->underlying.operator*(); }
const ValueType *operator->() const { return &this->operator*(); }
friend bool operator==(const ConstIterator &lhs, const ConstIterator &rhs) {
return lhs.underlying == rhs.underlying;
}
friend bool operator!=(const ConstIterator &lhs, const ConstIterator &rhs) {
return !(lhs == rhs);
}
friend bool operator==(const Iterator &lhs, const ConstIterator &rhs) {
return lhs == rhs.underlying;
}
friend bool operator!=(const Iterator &lhs, const ConstIterator &rhs) {
return !(lhs == rhs);
}
friend bool operator==(const ConstIterator &lhs, const Iterator &rhs) {
return lhs.underlying == rhs;
}
friend bool operator!=(const ConstIterator &lhs, const Iterator &rhs) {
return !(lhs == rhs);
}
};
class ReverseIterator {
Iterator underlying;
ReverseIterator(const Iterator &underlying) : underlying{underlying} {}
public:
friend Map;
ReverseIterator() = delete;
ReverseIterator(const ReverseIterator &) = default;
~ReverseIterator() = default;
ReverseIterator &operator=(const ReverseIterator &) = default;
ReverseIterator &operator++() {
--underlying;
return *this;
}
ReverseIterator operator++(int) {
auto copy = *this;
this->operator++();
return copy;
}
ReverseIterator &operator--() {
++underlying;
return *this;
}
ReverseIterator operator--(int) {
auto copy = *this;
this->operator++();
return copy;
}
const ValueType &operator*() const { return this->underlying.operator*(); }
const ValueType *operator->() const { return &this->operator*(); }
};
Map() : root{}, _size{0} {} Map() : root{}, _size{0} {}
Map(const Map &rhs) : root{rhs.root}, _size{rhs._size} {} Map(const Map &rhs) : root{rhs.root}, _size{rhs._size} {}
Map(Map &&rhs) : root{std::move(rhs.root)}, _size{rhs._size} {} Map(Map &&rhs) : root{std::move(rhs.root)}, _size{rhs._size} {}
@ -394,10 +544,14 @@ public:
this->_size = rhs._size; this->_size = rhs._size;
return *this; return *this;
} }
Map(std::initializer_list<std::pair<const Key_T, Mapped_T>> items) : Map{} {
this->insert(items.begin(), items.end());
}
void check() { void check() {
assert(!this->root || this->root.value().color == Color::Black); assert(!this->root || this->root.value().color == Color::Black);
} }
std::size_t size() { return this->_size; } std::size_t size() { return this->_size; }
bool empty() { return this->size() == 0; }
private: private:
// private helpers // private helpers
@ -421,18 +575,32 @@ private:
if (old_root->right) { if (old_root->right) {
old_root->right->parent = old_root.get(); 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();
}
root.value().set_child(dir, std::move(old_root)); root.value().set_child(dir, std::move(old_root));
root.value().child(dir)->restore_ordering();
if (root.value().left) { if (root.value().left) {
root.value().left->parent = &root.value(); root.value().left->parent = &root.value();
if (min == &root.value()) {
min = root.value().left.get();
}
} }
if (root.value().right) { if (root.value().right) {
root.value().right->parent = &root.value(); root.value().right->parent = &root.value();
if (max == &root.value()) {
max = root.value().right.get();
}
} }
} }
template <bool trace = false> template <bool trace = false>
std::pair<Node *, Direction> locate(const Key_T &key) { std::pair<Node const *, Direction> locate(const Key_T &key) const {
Node *ret_parent; Node const *ret_parent;
Direction ret_dir; Direction ret_dir;
// map is empty // map is empty
if (!this->root.has_value()) { if (!this->root.has_value()) {
@ -639,22 +807,22 @@ public:
return this->end(); return this->end();
} }
if (parent->child(dir) != nullptr) { if (parent->child(dir) != nullptr) {
return Iterator{parent->child(dir), nullptr}; return Iterator{const_cast<Node *>(parent->child(dir)), nullptr};
} }
return this->end(); return this->end();
} }
Iterator find_trace(const Key_T &key) { ConstIterator find(const Key_T &key) const {
auto [parent, dir] = locate<true>(key); auto [parent, dir] = locate(key);
if (parent == nullptr) { if (parent == nullptr) {
if (this->root.has_value()) { if (this->root.has_value()) {
if (this->root.value().val.first == key) { if (this->root.value().val.first == key) {
return Iterator{&this->root.value()}; return Iterator{const_cast<Node *>(&this->root.value())};
} }
} }
return this->end(); return this->end();
} }
if (parent->child(dir) != nullptr) { if (parent->child(dir) != nullptr) {
return Iterator{parent->child(dir), nullptr}; return Iterator{const_cast<Node *>(parent->child(dir)), nullptr};
} }
return this->end(); return this->end();
} }
@ -671,6 +839,9 @@ public:
} else { } else {
this->root = Node{val, this}; this->root = Node{val, this};
this->root.value().color = Color::Black; this->root.value().color = Color::Black;
this->min = &this->root.value();
this->max = &this->root.value();
this->_size++;
return std::make_pair(Iterator{&root.value()}, true); return std::make_pair(Iterator{&root.value()}, true);
} }
} }
@ -678,21 +849,35 @@ public:
// non-root node // non-root node
if (parent->child(dir)) { if (parent->child(dir)) {
// node already present // node already present
return std::make_pair(Iterator{parent->child(dir)}, false); return std::make_pair(Iterator{const_cast<Node *>(parent->child(dir))},
false);
} }
// need to insert non-root node // need to insert non-root node
Node *new_node = Map *m = const_cast<Map *>(this);
parent->set_child(dir, std::make_unique<Node>(Node{val, this})).get(); Node *new_node = const_cast<Node *>(parent)
->set_child(dir, std::make_unique<Node>(Node{val, m}))
.get();
new_node->restore_red_black_insert(dir); new_node->restore_red_black_insert(dir);
new_node->restore_ordering(); new_node->restore_ordering();
if (this->min == parent && dir == Direction::Left) {
this->min = new_node;
}
if (this->max == parent && dir == Direction::Right) {
this->max = new_node;
}
this->_size++;
return std::make_pair(Iterator{new_node}, true); return std::make_pair(Iterator{new_node}, true);
} }
void erase(Iterator pos) { void erase(Iterator pos) {
if (pos.underlying == nullptr) {
return;
}
this->_size--;
Node *before = pos.underlying->prev; Node *before = pos.underlying->prev;
Node *after = pos.underlying->next; Node *after = pos.underlying->next;
if (core_erase(pos.underlying)) { if (core_erase(pos.underlying)) {
pos.underlying->restore_ordering(); pos.underlying->restore_ordering();
} else { } else {
@ -701,12 +886,16 @@ public:
if (before->next != nullptr) { if (before->next != nullptr) {
before->next->prev = before; before->next->prev = before;
} }
} else {
this->min = after;
} }
if (after != nullptr) { if (after != nullptr) {
after->prev = after->calc_pred(); after->prev = after->calc_pred();
if (after->prev != nullptr) { if (after->prev != nullptr) {
after->prev->next = after; after->prev->next = after;
} }
} else {
this->max = before;
} }
} }
} }
@ -714,6 +903,46 @@ public:
// baseline iterator creation // baseline iterator creation
Iterator begin() { return Iterator{min, nullptr}; } Iterator begin() { return Iterator{min, nullptr}; }
Iterator end() { return Iterator{nullptr, max}; } Iterator end() { return Iterator{nullptr, max}; }
ConstIterator begin() const { return Iterator{min, nullptr}; }
ConstIterator end() const { return Iterator{nullptr, max}; }
ReverseIterator rbegin() { return Iterator{max, nullptr}; }
ReverseIterator rend() { return Iterator{nullptr, min}; }
// misc that can be implemented with the above or trivially
void clear() {
this->root = std::move(std::nullopt);
this->_size = 0;
}
Mapped_T &at(const Key_T &key) {
auto ret = this->find(key);
if (ret == this->end()) {
throw std::out_of_range{"key not in map"};
}
return (*ret).second;
}
const Mapped_T &at(const Key_T &key) const {
auto ret = this->find(key);
if (ret == this->end()) {
throw std::out_of_range{"key not in map"};
}
return (*ret).first;
}
Mapped_T &operator[](const Key_T &key) {
this->insert({key, {}});
return this->at(key);
}
template <typename IT_T> void insert(IT_T range_beg, IT_T range_end) {
while (range_beg != range_end) {
auto [first, second] = *range_beg;
this->insert(std::make_pair(first, second));
++range_beg;
}
}
void erase(const Key_T &key) { this->erase(this->find(key)); }
// TODO:
friend bool operator==(const Map &lhs, const Map &rhs) { assert(false); }
friend bool operator!=(const Map &lhs, const Map &rhs) { assert(false); }
friend bool operator<(const Map &lhs, const Map &rhs) { assert(false); }
}; };
} // namespace cs440 } // namespace cs440
#endif #endif

30
t.cpp
View file

@ -1,22 +1,20 @@
#include "Map.hpp" #include "Map.hpp"
#include <utility>
template class cs440::Map<int, int>; template class cs440::Map<int, int>;
int main(void) { int main(void) {
cs440::Map<int, int> a; // cs440::Map<int, int> a;
for (std::size_t i = 1; i <= 10; i++) { // for (std::size_t i = 10; i >= 1; i--) {
a.insert({i, i}); // a.insert({i, i});
a.check(); // for (std::size_t j = 10; j >= i; j--) {
for (std::size_t j = 1; j <= i; j++) { // }
a.find(j).check(); // }
} // for (std::size_t i = 10; i >= 5; i--) {
} // std::cout << i << std::endl;
for (std::size_t i = 1; i <= 10; i++) { // auto b = a.find(i);
a.find(i).check(); // a.erase(b);
} // for (std::size_t j = 1; j <= i; j++) {
for (std::size_t i = 1; i <= 5; i++) { // }
std::cout << i << std::endl; // }
auto b = a.find(i);
a.erase(b);
}
return 0; return 0;
} }