Bladeren bron

feat(map): add template container map

greatbridf 2 jaren geleden
bovenliggende
commit
a1ddb6a031
3 gewijzigde bestanden met toevoegingen van 712 en 0 verwijderingen
  1. 1 0
      CMakeLists.txt
  2. 16 0
      include/types/cplusplus.hpp
  3. 695 0
      include/types/map.hpp

+ 1 - 0
CMakeLists.txt

@@ -95,6 +95,7 @@ set(KERNEL_MAIN_SOURCES src/fs/fat.cpp
                         include/types/buffer.h
                         include/types/elf.hpp
                         include/types/hash_map.hpp
+                        include/types/map.hpp
                         include/types/pair.hpp
                         include/types/types.h
                         include/types/size.h

+ 16 - 0
include/types/cplusplus.hpp

@@ -17,6 +17,15 @@ using false_type = constant_value<bool, false>;
 
 namespace types::traits {
 
+template <bool Expression, typename TTrue, typename TFalse>
+struct condition {
+    using type = TFalse;
+};
+template <typename TTrue, typename TFalse>
+struct condition<true, TTrue, TFalse> {
+    using type = TTrue;
+};
+
 template <typename T>
 struct remove_pointer {
     using type = T;
@@ -86,6 +95,13 @@ template <typename T>
 struct is_pointer<T*> : true_type {
 };
 
+template <typename T>
+struct is_const : public false_type {
+};
+template <typename T>
+struct is_const<const T> : public true_type {
+};
+
 template <typename T>
 struct decay {
 private:

+ 695 - 0
include/types/map.hpp

@@ -0,0 +1,695 @@
+#pragma once
+
+#include <types/allocator.hpp>
+#include <types/cplusplus.hpp>
+#include <types/pair.hpp>
+#include <types/types.h>
+
+namespace types {
+
+template <typename Key, typename Value, template <typename _T> class _Allocator = kernel_allocator>
+class map {
+public:
+    using key_type = typename traits::add_const<Key>::type;
+    using value_type = Value;
+    using pair_type = pair<key_type, value_type>;
+
+    struct node {
+        node* parent = nullptr;
+
+        node* left = nullptr;
+        node* right = nullptr;
+
+        enum class node_color {
+            RED,
+            BLACK,
+        } color
+            = node_color::RED;
+
+        pair_type v;
+
+        constexpr node(pair_type&& pair)
+            : v(move(pair))
+        {
+        }
+        constexpr node(const pair_type& pair)
+            : v(pair)
+        {
+        }
+
+        constexpr node* grandparent(void) const
+        {
+            return this->parent->parent;
+        }
+
+        constexpr node* uncle(void) const
+        {
+            node* pp = this->grandparent();
+            return (this->parent == pp->left) ? pp->right : pp->left;
+        }
+
+        constexpr node* leftmost(void)
+        {
+            node* nd = this;
+            while (nd->left)
+                nd = nd->left;
+            return nd;
+        }
+
+        constexpr const node* leftmost(void) const
+        {
+            const node* nd = this;
+            while (nd->left)
+                nd = nd->left;
+            return nd;
+        }
+
+        constexpr node* rightmost(void)
+        {
+            node* nd = this;
+            while (nd->right)
+                nd = nd->right;
+            return nd;
+        }
+
+        constexpr const node* rightmost(void) const
+        {
+            const node* nd = this;
+            while (nd->right)
+                nd = nd->right;
+            return nd;
+        }
+
+        constexpr node* next(void)
+        {
+            if (this->right) {
+                return this->right->leftmost();
+            } else {
+                if (this->is_root()) {
+                    return nullptr;
+                } else if (this->is_left_child()) {
+                    return this->parent;
+                } else {
+                    node* ret = this;
+                    do {
+                        ret = ret->parent;
+                    } while (!ret->is_root() && !ret->is_left_child());
+                    return ret->parent;
+                }
+            }
+        }
+
+        constexpr const node* next(void) const
+        {
+            if (this->right) {
+                return this->right->leftmost();
+            } else {
+                if (this->is_root()) {
+                    return nullptr;
+                } else if (this->is_left_child()) {
+                    return this->parent;
+                } else {
+                    const node* ret = this;
+                    do {
+                        ret = ret->parent;
+                    } while (!ret->is_root() && !ret->is_left_child());
+                    return ret->parent;
+                }
+            }
+        }
+
+        constexpr node* prev(void)
+        {
+            if (this->left) {
+                return this->left->rightmost();
+            } else {
+                if (this->is_root()) {
+                    return nullptr;
+                } else if (this->is_right_child()) {
+                    return this->parent;
+                } else {
+                    node* ret = this;
+                    do {
+                        ret = ret->parent;
+                    } while (!ret->is_root() && !ret->is_right_child());
+                    return ret->parent;
+                }
+            }
+        }
+
+        static constexpr bool is_red(node* nd)
+        {
+            return nd && nd->color == node_color::RED;
+        }
+        static constexpr bool is_black(node* nd)
+        {
+            return !node::is_red(nd);
+        }
+
+        constexpr const node* prev(void) const
+        {
+            if (this->left) {
+                return this->left->rightmost();
+            } else {
+                if (this->is_root()) {
+                    return nullptr;
+                } else if (this->is_right_child()) {
+                    return this->parent;
+                } else {
+                    const node* ret = this;
+                    do {
+                        ret = ret->parent;
+                    } while (!ret->is_root() && !ret->is_right_child());
+                    return ret->parent;
+                }
+            }
+        }
+
+        constexpr bool is_root(void) const
+        {
+            return this->parent == nullptr;
+        }
+
+        constexpr bool is_full(void) const
+        {
+            return this->left && this->right;
+        }
+
+        constexpr bool has_child(void) const
+        {
+            return this->left || this->right;
+        }
+
+        constexpr bool is_leaf(void) const
+        {
+            return !this->has_child();
+        }
+
+        constexpr bool is_left_child(void) const
+        {
+            return this == this->parent->left;
+        }
+
+        constexpr bool is_right_child(void) const
+        {
+            return this == this->parent->right;
+        }
+
+        constexpr void tored(void)
+        {
+            this->color = node_color::RED;
+        }
+        constexpr void toblack(void)
+        {
+            this->color = node_color::BLACK;
+        }
+
+        static constexpr void swap(node* first, node* second)
+        {
+            node* p = first->parent;
+            node* cl = first->left;
+            node* cr = first->right;
+
+            if (node::is_red(first)) {
+                first->color = second->color;
+                second->color = node_color::RED;
+            } else {
+                first->color = second->color;
+                second->color = node_color::BLACK;
+            }
+
+            if (!first->is_root()) {
+                if (first->is_left_child())
+                    p->left = second;
+                else
+                    p->right = second;
+            }
+            if (cl)
+                cl->parent = second;
+            if (cr)
+                cr->parent = second;
+
+            first->parent = second->parent;
+            first->left = second->left;
+            first->right = second->right;
+
+            if (!second->is_root()) {
+                if (second->is_left_child())
+                    second->parent->left = first;
+                else
+                    second->parent->right = first;
+            }
+            if (second->left)
+                second->left->parent = first;
+            if (second->right)
+                second->right->parent = first;
+
+            second->parent = p;
+            second->left = cl;
+            second->right = cr;
+        }
+    };
+
+    using allocator_type = _Allocator<node>;
+
+    template <bool Const>
+    class iterator {
+    private:
+        static constexpr bool _is_const_iterator = Const;
+
+    public:
+        using node_pointer_type = typename traits::condition<_is_const_iterator, const node*, node*>::type;
+        using value_type = typename traits::condition<_is_const_iterator, const pair_type, pair_type>::type;
+        using pointer_type = typename traits::add_pointer<value_type>::type;
+        using reference_type = typename traits::add_reference<value_type>::type;
+
+        friend class map;
+
+    private:
+        node_pointer_type p;
+
+    public:
+        explicit constexpr iterator(node_pointer_type ptr)
+            : p { ptr }
+        {
+        }
+
+        constexpr iterator(const iterator& iter)
+            : p { iter.p }
+        {
+        }
+
+        constexpr iterator(iterator&& iter)
+            : p { iter.p }
+        {
+            iter.p = nullptr;
+        }
+
+        constexpr ~iterator()
+        {
+#ifndef NDEBUG
+            p = nullptr;
+#endif
+        }
+
+        constexpr iterator& operator=(const iterator& iter)
+        {
+            p = iter.p;
+        }
+
+        constexpr iterator& operator=(iterator&& iter)
+        {
+            p = iter.p;
+            iter.p = nullptr;
+        }
+
+        constexpr bool operator==(const iterator& iter) const
+        {
+            return p == iter.p;
+        }
+
+        constexpr bool operator!=(const iterator& iter) const
+        {
+            return !this->operator==(iter);
+        }
+
+        constexpr reference_type operator*(void) const
+        {
+            return p->v;
+        }
+
+        constexpr pointer_type operator&(void) const
+        {
+            return &p->v;
+        }
+
+        constexpr pointer_type operator->(void) const
+        {
+            return this->operator&();
+        }
+
+        constexpr iterator& operator++(void)
+        {
+            p = p->next();
+            return *this;
+        }
+
+        constexpr iterator operator++(int)
+        {
+            iterator ret(p);
+
+            (void)this->operator++();
+
+            return ret;
+        }
+
+        constexpr iterator& operator--(void)
+        {
+            p = p->prev();
+            return *this;
+        }
+
+        constexpr iterator operator--(int)
+        {
+            iterator ret(p);
+
+            (void)this->operator--();
+
+            return ret;
+        }
+    };
+
+    using iterator_type = iterator<false>;
+    using const_iterator_type = iterator<true>;
+
+private:
+    node* root = nullptr;
+
+private:
+    static constexpr node* newnode(node* parent, const pair_type& val)
+    {
+        auto* ptr = allocator_traits<allocator_type>::allocate_and_construct(val);
+        ptr->parent = parent;
+        return ptr;
+    }
+    static constexpr node* newnode(node* parent, pair_type&& val)
+    {
+        auto* ptr = allocator_traits<allocator_type>::allocate_and_construct(move(val));
+        ptr->parent = parent;
+        return ptr;
+    }
+    static constexpr void delnode(node* nd)
+    {
+        allocator_traits<allocator_type>::deconstruct_and_deallocate(nd);
+    }
+
+    constexpr void rotateleft(node* rt)
+    {
+        node* nrt = rt->right;
+
+        if (!rt->is_root()) {
+            if (rt->is_left_child()) {
+                rt->parent->left = nrt;
+            } else {
+                rt->parent->right = nrt;
+            }
+        } else {
+            this->root = nrt;
+        }
+
+        nrt->parent = rt->parent;
+        rt->parent = nrt;
+
+        rt->right = nrt->left;
+        nrt->left = rt;
+    }
+
+    constexpr void rotateright(node* rt)
+    {
+        node* nrt = rt->left;
+
+        if (!rt->is_root()) {
+            if (rt->is_left_child()) {
+                rt->parent->left = nrt;
+            } else {
+                rt->parent->right = nrt;
+            }
+        } else {
+            this->root = nrt;
+        }
+
+        nrt->parent = rt->parent;
+        rt->parent = nrt;
+
+        rt->left = nrt->right;
+        nrt->right = rt;
+    }
+
+    constexpr void balance(node* nd)
+    {
+        if (nd->is_root()) {
+            nd->toblack();
+            return;
+        }
+
+        if (node::is_black(nd->parent))
+            return;
+
+        node* p = nd->parent;
+        node* pp = nd->grandparent();
+        node* uncle = nd->uncle();
+
+        if (node::is_red(uncle)) {
+            p->toblack();
+            uncle->toblack();
+            pp->tored();
+            this->balance(pp);
+            return;
+        }
+
+        if (p->is_left_child()) {
+            if (nd->is_left_child()) {
+                p->toblack();
+                pp->tored();
+                this->rotateright(pp);
+            } else {
+                this->rotateleft(p);
+                this->balance(p);
+            }
+        } else {
+            if (nd->is_right_child()) {
+                p->toblack();
+                pp->tored();
+                this->rotateleft(pp);
+            } else {
+                this->rotateright(p);
+                this->balance(p);
+            }
+        }
+    }
+
+    constexpr node* _find(const key_type& key) const
+    {
+        node* cur = root;
+
+        if (unlikely(!cur))
+            return nullptr;
+
+        for (;;) {
+            if (cur->v.key == key)
+                return cur;
+
+            if (key < cur->v.key)
+                cur = cur->left;
+            else
+                cur = cur->right;
+        }
+    }
+
+    // this function DOES NOT dellocate the node
+    // caller is responsible for freeing the memory
+    // @param: nd is guaranteed to be a leaf node
+    constexpr void _erase(node* nd)
+    {
+        if (node::is_black(nd)) {
+            node* p = nd->parent;
+            node* s = nullptr;
+            if (nd->is_left_child())
+                s = p->right;
+            else
+                s = p->left;
+
+            if (node::is_red(s)) {
+                p->tored();
+                s->toblack();
+                if (nd->is_right_child()) {
+                    this->rotateright(p);
+                    s = p->left;
+                } else {
+                    this->rotateleft(p);
+                    s = p->right;
+                }
+            }
+
+            node* r = nullptr;
+            if (node::is_red(s->left)) {
+                r = s->left;
+                if (s->is_left_child()) {
+                    r->toblack();
+                    s->color = p->color;
+                    this->rotateright(p);
+                    p->toblack();
+                } else {
+                    r->color = p->color;
+                    this->rotateright(s);
+                    this->rotateleft(p);
+                    p->toblack();
+                }
+            } else if (node::is_red(s->right)) {
+                r = s->right;
+                if (s->is_left_child()) {
+                    r->color = p->color;
+                    this->rotateleft(s);
+                    this->rotateright(p);
+                    p->toblack();
+                } else {
+                    r->toblack();
+                    s->color = p->color;
+                    this->rotateleft(p);
+                    p->toblack();
+                }
+            } else {
+                s->tored();
+                this->_erase(p);
+            }
+        }
+    }
+
+public:
+    constexpr iterator_type end(void)
+    {
+        return iterator_type(nullptr);
+    }
+    constexpr const_iterator_type end(void) const
+    {
+        return const_iterator_type(nullptr);
+    }
+    constexpr const_iterator_type cend(void) const
+    {
+        return const_iterator_type(nullptr);
+    }
+
+    constexpr iterator_type begin(void)
+    {
+        return root ? iterator_type(root->leftmost()) : end();
+    }
+    constexpr const_iterator_type begin(void) const
+    {
+        return root ? const_iterator_type(root->leftmost()) : end();
+    }
+    constexpr const_iterator_type cbegin(void) const
+    {
+        return root ? const_iterator_type(root->leftmost()) : end();
+    }
+
+    constexpr iterator_type find(const key_type& key)
+    {
+        return iterator_type(_find(key));
+    }
+    constexpr const_iterator_type find(const key_type& key) const
+    {
+        return const_iterator_type(_find(key));
+    }
+
+    constexpr iterator_type insert(pair_type&& val)
+    {
+        node* cur = root;
+
+        while (likely(cur)) {
+            if (val.key < cur->v.key) {
+                if (!cur->left) {
+                    node* nd = newnode(cur, move(val));
+                    cur->left = nd;
+                    this->balance(nd);
+                    return iterator_type(nd);
+                } else {
+                    cur = cur->left;
+                }
+            } else {
+                if (!cur->right) {
+                    node* nd = newnode(cur, move(val));
+                    cur->right = nd;
+                    this->balance(nd);
+                    return iterator_type(nd);
+                } else {
+                    cur = cur->right;
+                }
+            }
+        }
+
+        root = newnode(nullptr, move(val));
+        root->toblack();
+        return iterator_type(root);
+    }
+
+    constexpr iterator_type erase(const iterator_type& iter)
+    {
+        node* nd = iter.p;
+        if (!nd)
+            return end();
+
+        if (nd->is_root() && nd->is_leaf()) {
+            delnode(nd);
+            root = nullptr;
+            return end();
+        }
+
+        node* next = nd->next();
+
+        while (!nd->is_leaf()) {
+            if (nd->is_root())
+                this->root = nd->right->leftmost();
+            node::swap(nd, nd->right->leftmost());
+        }
+
+        this->_erase(nd);
+
+        if (nd->is_left_child())
+            nd->parent->left = nullptr;
+        else
+            nd->parent->right = nullptr;
+
+        delnode(nd);
+
+        return iterator_type(next);
+    }
+
+    constexpr void remove(const key_type& key)
+    {
+        auto iter = this->find(key);
+        if (iter != this->end())
+            this->erase(iter);
+    }
+
+    // destroy a subtree without adjusting nodes to maintain binary tree properties
+    constexpr void destroy(node* nd)
+    {
+        if (nd) {
+            this->destroy(nd->left);
+            this->destroy(nd->right);
+            delnode(nd);
+        }
+    }
+
+    explicit constexpr map(void)
+    {
+    }
+    constexpr map(const map& val)
+    {
+        for (const auto& item : val)
+            this->insert(item);
+    }
+    constexpr map(map&& val)
+        : root(val.root)
+    {
+        val.root = nullptr;
+    }
+    constexpr map& operator=(const map& val)
+    {
+        this->destroy(root);
+        for (const auto& item : val)
+            this->insert(item);
+    }
+    constexpr map& operator=(map&& val)
+    {
+        this->destroy(root);
+        root = val.root;
+        val.root = nullptr;
+    }
+    constexpr ~map()
+    {
+        this->destroy(root);
+    }
+};
+
+} // namespace types