slowly working through given tests to get Map fully working in all functionality
This commit is contained in:
parent
315a200c9b
commit
ce0f5f7ef0
2 changed files with 125 additions and 137 deletions
105
Map.hpp
105
Map.hpp
|
@ -4,7 +4,6 @@
|
|||
// uncomment on submission/performance test
|
||||
// #define NDEBUG
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
|
@ -32,8 +31,8 @@ template <typename Key_T, typename Mapped_T> class Map {
|
|||
|
||||
struct Node {
|
||||
int valid = 0x13371337;
|
||||
Node *parent;
|
||||
internal_ValueType val;
|
||||
Node *parent = nullptr;
|
||||
std::unique_ptr<internal_ValueType> val;
|
||||
std::unique_ptr<Node> left;
|
||||
std::unique_ptr<Node> right;
|
||||
Color color;
|
||||
|
@ -41,13 +40,14 @@ template <typename Key_T, typename Mapped_T> 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<Node>(*rhs.left)},
|
||||
right{std::make_unique<Node>(*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<Node>(*rhs.left) : nullptr},
|
||||
right{rhs.right ? std::make_unique<Node>(*rhs.right) : nullptr},
|
||||
color{rhs.color}, prev{nullptr}, next{nullptr}, map{rhs.map} {
|
||||
this->valid = 0x13371337;
|
||||
|
||||
if (this->left) {
|
||||
|
@ -64,11 +64,7 @@ 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} {
|
||||
// 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 <typename Key_T, typename Mapped_T> class Map {
|
|||
// to a rotation where parent can get wonky
|
||||
// this->parent
|
||||
|
||||
this->val = rhs.val;
|
||||
this->left = std::make_unique<Node>(*rhs.left);
|
||||
this->right = std::make_unique<Node>(*rhs.right);
|
||||
this->val =
|
||||
rhs.val ? std::unique_ptr<internal_ValueType>{new internal_ValueType{
|
||||
*rhs.val}}
|
||||
: nullptr;
|
||||
this->left = rhs.left ? std::make_unique<Node>(*rhs.left) : nullptr;
|
||||
this->right = rhs.right ? std::make_unique<Node>(*rhs.right) : nullptr;
|
||||
this->color = rhs.color;
|
||||
this->valid = 0x13371337;
|
||||
|
||||
|
@ -110,7 +109,7 @@ template <typename Key_T, typename Mapped_T> 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<Node *>(&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;
|
||||
|
|
157
minimal.cpp
157
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<MyKeyType, MyDefaultConstructible>;
|
||||
|
||||
|
||||
int main() {
|
||||
cs440::Map<MyKeyType, MyValueType> 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<MyKeyType, MyValueType> 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<MyKeyType, MyDefaultConstructible> m2{{8, 9}};
|
||||
m2[10]; // should default construct these values
|
||||
m2[15];
|
||||
cs440::Map<MyKeyType, MyDefaultConstructible> m2{{8, 9}};
|
||||
m2[10]; // should default construct these values
|
||||
m2[15];
|
||||
|
||||
cs440::Map<MyKeyType, MyAssignable> m3{{6, 7}};
|
||||
m3[20] = {5}; // move assign
|
||||
MyAssignable ma{1};
|
||||
m3[10] = ma; //copy assign
|
||||
cs440::Map<MyKeyType, MyAssignable> m3{{6, 7}};
|
||||
m3[20] = {5}; // move assign
|
||||
MyAssignable ma{1};
|
||||
m3[10] = ma; // copy assign
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue