// commenting everything out when I commit so all commits my code technically // compiles #include #include #include #include #include #include #include #include #include // everything is super interconnected so some forward declarations are needed at // various points namespace cs440 { template class Map; namespace { enum class Color { Red, Black }; template struct BookKeeping { friend class Map; using ValueType = std::pair; Map &parent; ValueType value; std::size_t self; Color color; std::optional next; std::optional prev; }; } // namespace // https://en.wikipedia.org/wiki/Red%E2%80%93black_tree template class Map { private: using ValueType = std::pair; // idx 0 = root // left = parent * 2 + 1 // right = parent * 2 + 2 std::vector>> store; std::vector coloration; public: class Iterator; class ConstIterator; class ReverseIterator; friend class Iterator; friend class ConstIterator; friend class ReverseIterator; friend struct BookKeeping; // TODO: Iterator functionality class Iterator { friend class Map; friend struct BookKeeping; public: private: enum class PastElem { start, end, neither }; // pointer needed so we can replace as needed BookKeeping *parent; // TODO: next/prev found in bookkeeping // Note: only used when past first/last element PastElem use; std::optional next_or_prev; Iterator(std::optional> &parent) : parent{&parent}, use{PastElem::neither}, next_or_prev{std::nullopt} {} public: Iterator() = delete; 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: friend class Map; friend class Iterator; using underlying = Iterator; private: underlying store_iter; ConstIterator(underlying iter) : store_iter{iter} {} public: ConstIterator() = delete; 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: friend class Map; using underlying = typename std::vector>::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 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(); } // TODO: Iterator creation Iterator begin() {} Iterator end() {} ConstIterator begin() const {} ConstIterator end() const {} ConstIterator cbegin() const {} ConstIterator cend() const {} ReverseIterator rbegin() {} ReverseIterator rend() {} // TODO: actually return an iterator from find and deal with error cases // correctly, also need to update for new bookkeeping type 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); } private: Color getColor(std::size_t i) { if (this->store.size() <= i) { return Color::Black; } if (!this->store.at(i).has_value()) { return Color::Black; } return this->store.at(i).value().color; } std::size_t find_null(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) { if (idx * 2 + 1 > store.size() || !store.at(idx * 2 + 1).has_value()) { idx = idx * 2 + 1; break; } idx = idx * 2 + 1; } else { if (idx * 2 + 2 > store.size() || !store.at(idx * 2 + 2).has_value()) { idx = idx * 2 + 2; break; } idx = idx * 2 + 2; } } return idx; } enum class Direction { left, right }; void insert_helper(std::size_t idx, BookKeeping to_insert) { // might as well make sure to_insert.color = Color::Red; std::size_t parent_idx; Direction relation; if (idx % 2 == 1) { parent_idx = (idx - 1) / 2; relation = Direction::left; } else { parent_idx = (idx - 1) / 2; relation = Direction::right; } BookKeeping &parent = this->store.at(parent_idx).value(); } public: // TODO: single insert // OH NO IT SHOULD BE RED-BLACK std::pair insert(const ValueType &val) { BookKeeping new_node; new_node.color = Color::Red; new_node.value = val; new_node.parent = *this; if (this->store.size() == 0) { new_node.self = 0; this->store.push_back(new_node); } } template 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