Browse Source

feat: vector and allocator improvement

greatbridf 3 years ago
parent
commit
9f1b0d0b7d
4 changed files with 326 additions and 53 deletions
  1. 2 0
      CMakeLists.txt
  2. 75 0
      include/types/allocator.hpp
  3. 8 53
      include/types/list.hpp
  4. 241 0
      include/types/vector.hpp

+ 2 - 0
CMakeLists.txt

@@ -78,7 +78,9 @@ set(KERNEL_MAIN_SOURCES src/kernel_main.c
                         include/types/status.h
                         include/types/stdint.h
                         include/types/list.h
+                        include/types/allocator.hpp
                         include/types/list.hpp
+                        include/types/vector.hpp
                         include/kernel_main.h
                         )
 add_library(kernel_main STATIC ${KERNEL_MAIN_SOURCES})

+ 75 - 0
include/types/allocator.hpp

@@ -0,0 +1,75 @@
+#pragma once
+#include <types/types.h>
+
+inline void* operator new(size_t, void* ptr)
+{
+    return ptr;
+}
+
+namespace types {
+template <typename T>
+class kernel_allocator {
+public:
+    using value_type = T;
+
+    static value_type* allocate_memory(size_t count)
+    {
+        return static_cast<value_type*>(::k_malloc(sizeof(value_type) * count));
+    }
+
+    static void deallocate_memory(value_type* ptr)
+    {
+        ::k_free(ptr);
+    }
+};
+
+template <typename Allocator>
+class allocator_traits {
+public:
+    using value_type = typename Allocator::value_type;
+
+    static value_type* allocate(size_t count)
+    {
+        if (count == 0)
+            return nullptr;
+        return Allocator::allocate_memory(sizeof(value_type) * count);
+    }
+
+    template <typename... Args>
+    static value_type* construct(value_type* ptr, Args... args)
+    {
+        new (ptr) value_type(args...);
+        return ptr;
+    }
+
+    template <typename... Args>
+    static value_type* allocate_and_construct(Args... args)
+    {
+        auto* ptr = allocate(1);
+        construct(ptr, args...);
+        return ptr;
+    }
+
+    static void deconstruct(value_type* ptr)
+    {
+        if (!ptr)
+            return;
+        ptr->~value_type();
+    }
+
+    static void deallocate(value_type* ptr)
+    {
+        if (!ptr)
+            return;
+        Allocator::deallocate_memory(ptr);
+    }
+
+    static void deconstruct_and_deallocate(value_type* ptr)
+    {
+        if (!ptr)
+            return;
+        deconstruct(ptr);
+        deallocate(ptr);
+    }
+};
+} // namespace types

+ 8 - 53
include/types/list.hpp

@@ -1,56 +1,11 @@
 #pragma once
 
 #include <kernel/mem.h>
+#include <types/allocator.hpp>
 #include <types/types.h>
 
-inline void* operator new(size_t, void* ptr)
-{
-    return ptr;
-}
-
 namespace types {
 
-template <typename T>
-class kernel_allocator {
-public:
-    using value_type = T;
-
-    static value_type* allocate_memory(size_t count)
-    {
-        return static_cast<value_type*>(::k_malloc(sizeof(value_type) * count));
-    }
-
-    static void deallocate_memory(value_type* ptr)
-    {
-        ::k_free(ptr);
-    }
-};
-
-template <typename Allocator>
-class allocator_traits {
-public:
-    using value_type = typename Allocator::value_type;
-
-    static value_type* allocate_memory(size_t count)
-    {
-        return Allocator::allocate_memory(count);
-    }
-
-    template <typename... Args>
-    static value_type* allocate(Args... args)
-    {
-        value_type* ptr = allocate_memory(sizeof(value_type));
-        new (ptr) value_type(args...);
-        return ptr;
-    }
-
-    static void deallocate(value_type* ptr)
-    {
-        ptr->~value_type();
-        Allocator::deallocate_memory(ptr);
-    }
-};
-
 template <typename T, template <typename _value_type> class Allocator = kernel_allocator>
 class list {
 private:
@@ -192,8 +147,8 @@ private:
 public:
     list() noexcept
         // size is stored in the 'head' node
-        : head(allocator_traits<sentry_allocator_type>::allocate(0))
-        , tail(allocator_traits<sentry_allocator_type>::allocate(0))
+        : head(allocator_traits<sentry_allocator_type>::allocate_and_construct(0))
+        , tail(allocator_traits<sentry_allocator_type>::allocate_and_construct(0))
     {
         head->connect(tail);
         tail->connect(head);
@@ -204,8 +159,8 @@ public:
         for (auto iter = begin(); iter != end(); ++iter) {
             erase(iter);
         }
-        allocator_traits<sentry_allocator_type>::deallocate(static_cast<sentry_node_type*>(head));
-        allocator_traits<sentry_allocator_type>::deallocate(static_cast<sentry_node_type*>(tail));
+        allocator_traits<sentry_allocator_type>::deconstruct_and_deallocate(static_cast<sentry_node_type*>(head));
+        allocator_traits<sentry_allocator_type>::deconstruct_and_deallocate(static_cast<sentry_node_type*>(tail));
     }
 
     // TODO: find
@@ -215,14 +170,14 @@ public:
     {
         node_base_type* current_node = iter._node();
         current_node->prev->connect(current_node->next);
-        allocator_traits<allocator_type>::deallocate(static_cast<node_type*>(current_node));
+        allocator_traits<allocator_type>::deconstruct_and_deallocate(static_cast<node_type*>(current_node));
         --_size();
     }
 
     // insert the value v in front of the given iterator
     void insert(const iterator_type& iter, const value_type& v) noexcept
     {
-        node_base_type* new_node = allocator_traits<allocator_type>::allocate(v);
+        node_base_type* new_node = allocator_traits<allocator_type>::allocate_and_construct(v);
         iter._node()->prev->connect(new_node);
         new_node->connect(iter._node());
 
@@ -232,7 +187,7 @@ public:
     // insert the value v in front of the given iterator
     void insert(const iterator_type& iter, value_type&& v) noexcept
     {
-        node_base_type* new_node = allocator_traits<allocator_type>::allocate(v);
+        node_base_type* new_node = allocator_traits<allocator_type>::allocate_and_construct(v);
         iter._node().prev->connect(new_node);
         new_node->connect(iter._node());
 

+ 241 - 0
include/types/vector.hpp

@@ -0,0 +1,241 @@
+#pragma once
+
+#include <kernel/mem.h>
+#include <types/allocator.hpp>
+#include <types/types.h>
+
+namespace types {
+
+template <typename T, template <typename _value_type> class Allocator = kernel_allocator>
+class vector {
+public:
+    class iterator;
+
+    using value_type = T;
+    using pointer_type = value_type*;
+    using reference_type = value_type&;
+    using iterator_type = iterator;
+    using size_type = size_t;
+    using difference_type = ssize_t;
+    using index_type = size_type;
+    using allocator_type = Allocator<value_type>;
+
+public:
+    class iterator {
+    public:
+        explicit iterator(const iterator& iter) noexcept
+            : p(iter.p)
+        {
+        }
+
+        explicit iterator(iterator&& iter) noexcept
+            : p(iter.p)
+        {
+        }
+
+        explicit iterator(pointer_type p) noexcept
+            : p(p)
+        {
+        }
+
+        bool operator==(const iterator& iter) noexcept
+        {
+            return this->p == iter.p;
+        }
+
+        bool operator!=(const iterator& iter) noexcept
+        {
+            return !(*this == iter);
+        }
+
+        iterator& operator++() noexcept
+        {
+            ++p;
+            return *this;
+        }
+
+        iterator operator++(int) noexcept
+        {
+            iterator iter(*this);
+            ++p;
+            return iter;
+        }
+
+        iterator& operator--() noexcept
+        {
+            --p;
+            return *this;
+        }
+
+        iterator operator--(int) noexcept
+        {
+            iterator iter(*this);
+            --p;
+            return iter;
+        }
+
+        reference_type operator*() const noexcept
+        {
+            return *p;
+        }
+
+        pointer_type operator->() const noexcept
+        {
+            return p;
+        }
+
+    protected:
+        pointer_type p;
+    };
+
+public:
+    vector() noexcept
+        : m_size(0)
+    {
+        resize(1);
+    }
+
+    ~vector() noexcept
+    {
+        resize(0);
+    }
+
+    void resize(size_type n)
+    {
+        value_type* new_ptr = allocator_traits<allocator_type>::allocate(n);
+
+        m_capacity = n;
+        size_t orig_size = m_size;
+        if (m_size > m_capacity)
+            m_size = m_capacity;
+
+        for (size_t i = 0; i < m_size; ++i)
+            allocator_traits<allocator_type>::construct(new_ptr + i, _at(i));
+
+        for (size_t i = 0; i < orig_size; ++i)
+            allocator_traits<allocator_type>::deconstruct(m_arr + i);
+
+        allocator_traits<allocator_type>::deallocate(m_arr);
+        m_arr = new_ptr;
+    }
+
+    // TODO: find
+
+    // erase the node which iter points to
+    void erase(const iterator_type& iter) noexcept
+    {
+        allocator_traits<allocator_type>::deconstruct(iter.p);
+        --m_size;
+    }
+
+    // insert the value v in front of the given iterator
+    // void insert(const iterator_type& iter, const value_type& v) noexcept
+    // {
+    //     node_base_type* new_node = allocator_traits<allocator_type>::allocate(v);
+    //     iter._node()->prev->connect(new_node);
+    //     new_node->connect(iter._node());
+
+    //     ++_size();
+    // }
+
+    // insert the value v in front of the given iterator
+    // void insert(const iterator_type& iter, value_type&& v) noexcept
+    // {
+    //     node_base_type* new_node = allocator_traits<allocator_type>::allocate(v);
+    //     iter._node().prev->connect(new_node);
+    //     new_node->connect(iter._node());
+
+    //     ++_size();
+    // }
+
+    value_type* data(void) noexcept
+    {
+        return m_arr;
+    }
+
+    const value_type* data(void) const noexcept
+    {
+        return m_arr;
+    }
+
+    value_type& at(index_type i) noexcept
+    {
+        // TODO: boundary check
+        return _at(i);
+    }
+
+    const value_type& at(index_type i) const noexcept
+    {
+        // TODO: boundary check
+        return _at(i);
+    }
+
+    value_type& operator[](index_type i) noexcept
+    {
+        return at(i);
+    }
+
+    const value_type& operator[](index_type i) const noexcept
+    {
+        return at(i);
+    }
+
+    void push_back(const value_type& v) noexcept
+    {
+        if (m_size == m_capacity)
+            resize(m_capacity * 2);
+        allocator_traits<allocator_type>::construct(m_arr + m_size, v);
+        ++m_size;
+    }
+
+    void push_back(value_type&& v) noexcept
+    {
+        if (m_size == m_capacity)
+            resize(m_capacity * 2);
+        allocator_traits<allocator_type>::construct(m_arr + m_size, v);
+        ++m_size;
+    }
+
+    size_t size(void) const noexcept
+    {
+        return m_size;
+    }
+
+    iterator_type begin() noexcept
+    {
+        return iterator_type(m_arr);
+    }
+
+    iterator_type end() noexcept
+    {
+        return iterator_type(m_arr + m_size - 1);
+    }
+
+    bool empty(void) const noexcept
+    {
+        return size() == 0;
+    }
+
+    // TODO
+    // iterator_type cstart() noexcept;
+    // iterator_type cend() noexcept;
+
+    // iterator_type r_start() noexcept;
+    // iterator_type r_end() noexcept;
+
+    // iterator_type cr_start() noexcept;
+    // iterator_type cr_end() noexcept;
+
+private:
+    inline value_type& _at(index_type i)
+    {
+        return m_arr[i];
+    }
+
+private:
+    value_type* m_arr;
+    size_type m_capacity;
+    size_type m_size;
+};
+
+} // namespace types