Everything works via a bookkeeping type which tracks a bunch of stuff like the color and neighbors. This is needed to make the iterator go brrrr instead of needing to relocate the relevant tree node every time we want to increment the iterator.
312 lines
8.9 KiB
C++
312 lines
8.9 KiB
C++
// commenting everything out when I commit so all commits my code technically
|
|
// compiles
|
|
#include <algorithm>
|
|
#include <cstddef>
|
|
#include <deque>
|
|
#include <initializer_list>
|
|
#include <iterator>
|
|
#include <optional>
|
|
#include <stdexcept>
|
|
#include <utility>
|
|
#include <vector>
|
|
namespace cs440 {
|
|
|
|
template <typename Key_T, typename Mapped_T> class Map;
|
|
|
|
namespace {
|
|
enum class Color { Red, Black };
|
|
template <typename Key_T, typename Mapped_T> struct BookKeeping {
|
|
using ValueType = std::pair<const Key_T, Mapped_T>;
|
|
Map<Key_T, Mapped_T> &parent;
|
|
ValueType value;
|
|
std::size_t self;
|
|
std::size_t next;
|
|
std::size_t prev;
|
|
Color color;
|
|
};
|
|
} // namespace
|
|
// https://en.wikipedia.org/wiki/Red%E2%80%93black_tree
|
|
template <typename Key_T, typename Mapped_T> class Map {
|
|
private:
|
|
using ValueType = std::pair<const Key_T, Mapped_T>;
|
|
// idx 0 = root
|
|
// left = parent * 2 + 1
|
|
// right = parent * 2 + 2
|
|
std::vector<std::optional<BookKeeping<Key_T, Mapped_T>>> store;
|
|
std::vector<Color> coloration;
|
|
|
|
public:
|
|
class Iterator;
|
|
class ConstIterator;
|
|
class ReverseIterator;
|
|
|
|
friend class Iterator;
|
|
friend class ConstIterator;
|
|
friend class ReverseIterator;
|
|
// TODO: Iterator functionality
|
|
class Iterator {
|
|
public:
|
|
private:
|
|
BookKeeping<Key_T, Mapped_T> &parent;
|
|
// TODO: replace queues with functions that just go through the entire in
|
|
// order traversal and give the next/previous element
|
|
public:
|
|
Iterator() = delete;
|
|
Iterator(std::optional<BookKeeping<Key_T, Mapped_T>> &parent)
|
|
: parent{parent} {}
|
|
ConstIterator to_const() const { return ConstIterator(*this); }
|
|
Iterator &operator++() { return *this; }
|
|
Iterator operator++(int) {
|
|
Iterator tmp = *this;
|
|
++(*this);
|
|
return tmp;
|
|
}
|
|
Iterator &operator--() { return *this; }
|
|
Iterator operator--(int) {
|
|
Iterator tmp = *this;
|
|
--(*this);
|
|
return tmp;
|
|
}
|
|
ValueType &operator*() const { return parent.parent.at(parent.self); }
|
|
ValueType *operator->() const { return &**this; }
|
|
friend bool operator==(Iterator const &lhs, Iterator const &rhs) {
|
|
return lhs.store_iter == rhs.store_iter;
|
|
}
|
|
friend bool operator!=(Iterator const &lhs, Iterator const &rhs) {
|
|
return lhs.store_iter != rhs.store_iter;
|
|
}
|
|
friend bool operator==(ConstIterator const &lhs, Iterator const &rhs) {
|
|
return lhs == rhs.to_const();
|
|
}
|
|
friend bool operator!=(ConstIterator const &lhs, Iterator const &rhs) {
|
|
return lhs != rhs.to_const();
|
|
}
|
|
friend bool operator==(Iterator const &lhs, ConstIterator const &rhs) {
|
|
return lhs.to_const() == rhs;
|
|
}
|
|
friend bool operator!=(Iterator const &lhs, ConstIterator const &rhs) {
|
|
return lhs.to_const() != rhs;
|
|
}
|
|
};
|
|
class ConstIterator {
|
|
public:
|
|
using underlying = Iterator;
|
|
|
|
private:
|
|
underlying store_iter;
|
|
|
|
public:
|
|
ConstIterator() = delete;
|
|
ConstIterator(underlying iter) : store_iter{iter} {}
|
|
friend bool operator==(ConstIterator const &lhs, ConstIterator const &rhs) {
|
|
return lhs.store_iter == rhs.store_iter;
|
|
}
|
|
ConstIterator &operator++() {
|
|
++this->store_iter;
|
|
return *this;
|
|
}
|
|
ConstIterator operator++(int) {
|
|
ConstIterator tmp = *this;
|
|
this->store_iter++;
|
|
return tmp;
|
|
}
|
|
ConstIterator &operator--() {
|
|
--this->store_iter;
|
|
return *this;
|
|
}
|
|
ConstIterator operator--(int) {
|
|
ConstIterator tmp = *this;
|
|
this->store_iter--;
|
|
return tmp;
|
|
}
|
|
const ValueType &operator*() const { return *this->store_iter; }
|
|
const ValueType *operator->() const {
|
|
// I find this rather funny
|
|
return this->store_iter.operator->();
|
|
}
|
|
friend bool operator!=(ConstIterator const &lhs, ConstIterator const &rhs) {
|
|
return lhs.store_iter != rhs.store_iter;
|
|
}
|
|
};
|
|
class ReverseIterator {
|
|
public:
|
|
using underlying = typename std::vector<std::optional<ValueType>>::iterator;
|
|
|
|
private:
|
|
underlying store_iter;
|
|
|
|
public:
|
|
ReverseIterator() = delete;
|
|
ReverseIterator(underlying store_iter) : store_iter{store_iter} {}
|
|
ReverseIterator &operator++() {}
|
|
ReverseIterator operator++(int) {}
|
|
ReverseIterator &operator--() {}
|
|
ReverseIterator operator--(int) {}
|
|
ValueType &operator*() const {}
|
|
ValueType *operator->() const {}
|
|
friend bool operator==(ReverseIterator const &lhs,
|
|
ReverseIterator const &rhs) {
|
|
return lhs.store_iter == rhs.store_iter;
|
|
}
|
|
friend bool operator!=(ConstIterator const &lhs, ConstIterator const &rhs) {
|
|
return lhs.store_iter != rhs.store_iter;
|
|
}
|
|
};
|
|
Map() : store{} {}
|
|
Map(const Map &rhs) : store{rhs.store} {}
|
|
Map &operator=(const Map &rhs) { this->store = rhs.store; }
|
|
Map(std::initializer_list<ValueType> elems) : store{} {
|
|
this->insert(elems.begin(), elems.end());
|
|
}
|
|
// who cares we're using vector
|
|
~Map() {}
|
|
|
|
size_t size() const {
|
|
std::size_t count = 0;
|
|
for (auto &m_pair : this->store) {
|
|
count += m_pair.has_value() ? 1 : 0;
|
|
}
|
|
return count;
|
|
}
|
|
bool empty() const { return this->store.empty(); }
|
|
Iterator begin() {
|
|
std::size_t start = 0;
|
|
while (2 * (start - store.begin()) + 1 < store.size()) {
|
|
store = 2 * store + 2;
|
|
}
|
|
return Iterator(store.cbegin() + start);
|
|
}
|
|
Iterator end() { return Iterator(store.end()); }
|
|
ConstIterator begin() const {
|
|
std::size_t start = 0;
|
|
while (2 * (start - store.begin()) + 1 < store.size()) {
|
|
store = 2 * store + 2;
|
|
}
|
|
return ConstIterator(store.cbegin() + start);
|
|
}
|
|
ConstIterator end() const { return ConstIterator(store.cend()); }
|
|
ConstIterator cbegin() const { return this->begin(); }
|
|
ConstIterator cend() const { return this->end(); }
|
|
ReverseIterator rbegin() {
|
|
std::size_t start = 0;
|
|
while (2 * (start - store.begin()) + 1 < store.size()) {
|
|
store = 2 * store + 2;
|
|
}
|
|
return ReverseIterator(store.begin() + start);
|
|
}
|
|
ReverseIterator rend() { return ReverseIterator(store.end()); }
|
|
Iterator find(const Key_T &key) {
|
|
std::size_t idx = 0;
|
|
while (store[idx].first != key) {
|
|
if (idx >= store.size()) {
|
|
return this->end();
|
|
}
|
|
if (store[idx].first < key) {
|
|
idx = idx * 2 + 1;
|
|
} else {
|
|
idx = idx * 2 + 2;
|
|
}
|
|
}
|
|
}
|
|
ConstIterator find(const Key_T &key) const {
|
|
std::size_t idx = 0;
|
|
while (store[idx].first != key) {
|
|
if (idx >= store.size()) {
|
|
return this->end();
|
|
}
|
|
if (store[idx].first < key) {
|
|
idx = idx * 2 + 1;
|
|
} else {
|
|
idx = idx * 2 + 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
Mapped_T &at(const Key_T &key) {
|
|
std::size_t i = 0;
|
|
while (this->store.at(i).has_value()) {
|
|
switch (true) {
|
|
case this->store.at(i).first == key:
|
|
return this->store.at(i).second;
|
|
case this->store.at(i).first < key:
|
|
i = 2 * i + 1;
|
|
break;
|
|
case this->store.at(i).first > key:
|
|
i = 2 * i + 2;
|
|
break;
|
|
}
|
|
}
|
|
throw std::out_of_range{""};
|
|
}
|
|
const Mapped_T &at(const Key_T &key) const { return this->at(key); }
|
|
Mapped_T &operator[](const Key_T &key) { return this->at(key); }
|
|
|
|
// TODO: single insert
|
|
// OH NO IT SHOULD BE RED-BLACK
|
|
std ::pair<Iterator, bool> insert(const ValueType &) {}
|
|
template <typename IT_T> void insert(IT_T range_beg, IT_T range_end) {
|
|
std::for_each(range_beg, range_end,
|
|
[&](ValueType &val) { this->insert(val); });
|
|
}
|
|
// TODO: erase via iterator
|
|
void erase(Iterator pos) {
|
|
// RED BLACK TREE oh no
|
|
}
|
|
void erase(const Key_T &key) { this->erase(this->find(key)); }
|
|
void clear() { this->store = {}; }
|
|
friend bool operator==(const Map &lhs, const Map &rhs) {
|
|
if (lhs.store.size() != rhs.store.size()) {
|
|
return false;
|
|
}
|
|
auto liter = lhs.cbegin();
|
|
auto riter = rhs.cbegin();
|
|
// both must be the same length so this is fine
|
|
while (liter != lhs.cend()) {
|
|
if (*liter != *riter) {
|
|
return false;
|
|
}
|
|
liter++;
|
|
riter++;
|
|
}
|
|
return true;
|
|
}
|
|
friend bool operator!=(const Map &lhs, const Map &rhs) {
|
|
return !(lhs == rhs);
|
|
}
|
|
friend bool operator<(const Map &lhs, const Map &rhs) {
|
|
std::size_t lhs_i = 0;
|
|
std::size_t rhs_i = 0;
|
|
for (; lhs_i < lhs.store.size() && rhs_i < rhs.store.size();
|
|
lhs_i++, rhs_i++) {
|
|
bool lhs_exhaust = false;
|
|
while (!lhs.store[lhs_i].has_value()) {
|
|
lhs_i++;
|
|
if (lhs.store.size() >= lhs_i) {
|
|
lhs_exhaust = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool rhs_exhaust = false;
|
|
while (!rhs.store[rhs_i].has_value()) {
|
|
rhs_i++;
|
|
if (rhs.store.size() >= rhs_i) {
|
|
rhs_exhaust = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (lhs_exhaust && !rhs_exhaust) {
|
|
return true;
|
|
}
|
|
if (lhs_exhaust || rhs_exhaust) {
|
|
break;
|
|
}
|
|
if (lhs.store[lhs_i] != rhs.store[rhs_i]) {
|
|
return lhs.store[lhs_i] < rhs.store[rhs_i];
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
} // namespace cs440
|