mirror of
https://github.com/momo5502/hypervisor.git
synced 2025-04-20 05:55:44 +00:00
Add linked list
This commit is contained in:
parent
d1ad347e84
commit
a67e2ae833
38
src/driver/allocator.hpp
Normal file
38
src/driver/allocator.hpp
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "memory.hpp"
|
||||||
|
|
||||||
|
namespace utils
|
||||||
|
{
|
||||||
|
template <typename T>
|
||||||
|
concept IsAllocator = requires(size_t size, void* ptr)
|
||||||
|
{
|
||||||
|
T().free(T().allocate(size));
|
||||||
|
T().free(ptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AlignedAllocator
|
||||||
|
{
|
||||||
|
void* allocate(const size_t size)
|
||||||
|
{
|
||||||
|
return memory::allocate_aligned_memory(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(void* ptr)
|
||||||
|
{
|
||||||
|
memory::free_aligned_memory(ptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NonPagedAllocator
|
||||||
|
{
|
||||||
|
void* allocate(const size_t size)
|
||||||
|
{
|
||||||
|
return memory::allocate_non_paged_memory(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(void* ptr)
|
||||||
|
{
|
||||||
|
memory::free_non_paged_memory(ptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
295
src/driver/list.hpp
Normal file
295
src/driver/list.hpp
Normal file
@ -0,0 +1,295 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "allocator.hpp"
|
||||||
|
#include "exception.hpp"
|
||||||
|
#include "finally.hpp"
|
||||||
|
|
||||||
|
namespace utils
|
||||||
|
{
|
||||||
|
template <typename T, typename ObjectAllocator = NonPagedAllocator, typename ListAllocator = NonPagedAllocator>
|
||||||
|
requires IsAllocator<ObjectAllocator> && IsAllocator<ListAllocator>
|
||||||
|
class list
|
||||||
|
{
|
||||||
|
struct ListEntry
|
||||||
|
{
|
||||||
|
T* entry{nullptr};
|
||||||
|
ListEntry* next{nullptr};
|
||||||
|
|
||||||
|
void* this_base{nullptr};
|
||||||
|
void* entry_base{nullptr};
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
using type = T;
|
||||||
|
|
||||||
|
class iterator
|
||||||
|
{
|
||||||
|
friend list;
|
||||||
|
|
||||||
|
public:
|
||||||
|
iterator(ListEntry* entry = nullptr)
|
||||||
|
: entry_(entry)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
T* operator*() const
|
||||||
|
{
|
||||||
|
return this->entry_->entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
T* operator->() const
|
||||||
|
{
|
||||||
|
return this->entry_->entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const iterator& i) const
|
||||||
|
{
|
||||||
|
return this->entry_ == i.entry_;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator operator++() const
|
||||||
|
{
|
||||||
|
this->entry_ = this->entry_->next;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ListEntry* entry_{nullptr};
|
||||||
|
|
||||||
|
ListEntry* get_entry() const
|
||||||
|
{
|
||||||
|
return entry_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class const_iterator
|
||||||
|
{
|
||||||
|
friend list;
|
||||||
|
|
||||||
|
public:
|
||||||
|
const_iterator(ListEntry* entry = nullptr)
|
||||||
|
: entry_(entry)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const T* operator*() const
|
||||||
|
{
|
||||||
|
return this->entry_->entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
const T* operator->() const
|
||||||
|
{
|
||||||
|
return this->entry_->entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const const_iterator& i) const
|
||||||
|
{
|
||||||
|
return this->entry_ == i.entry_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator operator++() const
|
||||||
|
{
|
||||||
|
this->entry_ = this->entry_->next;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ListEntry* entry_{nullptr};
|
||||||
|
|
||||||
|
ListEntry* get_entry() const
|
||||||
|
{
|
||||||
|
return entry_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
list() = default;
|
||||||
|
|
||||||
|
~list()
|
||||||
|
{
|
||||||
|
this->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
list(const list& obj)
|
||||||
|
: list()
|
||||||
|
{
|
||||||
|
this->operator=(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
list(list&& obj) noexcept
|
||||||
|
: list()
|
||||||
|
{
|
||||||
|
this->operator=(std::move(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
list& operator=(const list& obj)
|
||||||
|
{
|
||||||
|
if (this != &obj)
|
||||||
|
{
|
||||||
|
this->clear();
|
||||||
|
|
||||||
|
for (const auto& i : obj)
|
||||||
|
{
|
||||||
|
this->push_back(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
list& operator=(list&& obj) noexcept
|
||||||
|
{
|
||||||
|
if (this != &obj)
|
||||||
|
{
|
||||||
|
this->clear();
|
||||||
|
|
||||||
|
this->entries_ = obj.entries_;
|
||||||
|
obj.entries_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
T& push_back(T obj)
|
||||||
|
{
|
||||||
|
auto** inseration_point = &this->entries_;
|
||||||
|
while (*inseration_point)
|
||||||
|
{
|
||||||
|
inseration_point = &(*inseration_point)->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* list_base = this->list_allocator_.allocate(sizeof(ListEntry) + alignof(ListEntry));
|
||||||
|
auto* entry_base = this->object_allocator_.allocate(sizeof(T) + alignof(T));
|
||||||
|
|
||||||
|
auto* entry = align_pointer<T>(entry_base);
|
||||||
|
auto* list_entry = align_pointer<ListEntry>(list_base);
|
||||||
|
|
||||||
|
list_entry->this_base = list_base;
|
||||||
|
list_entry->entry_base = entry_base;
|
||||||
|
list_entry->next = nullptr;
|
||||||
|
list_entry->entry = entry;
|
||||||
|
|
||||||
|
*inseration_point = list_entry;
|
||||||
|
|
||||||
|
new(entry) T(std::move(obj));
|
||||||
|
|
||||||
|
return *entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
T& operator[](const size_t index)
|
||||||
|
{
|
||||||
|
return this->at(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
const T& operator[](const size_t index) const
|
||||||
|
{
|
||||||
|
return this->at(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
T& at(const size_t index)
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
for (auto& obj : *this)
|
||||||
|
{
|
||||||
|
if (++i == index)
|
||||||
|
{
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::runtime_error("Out of bounds access");
|
||||||
|
}
|
||||||
|
|
||||||
|
const T& at(const size_t index) const
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
for (const auto& obj : *this)
|
||||||
|
{
|
||||||
|
if (++i == index)
|
||||||
|
{
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::runtime_error("Out of bounds access");
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
while (this->entries_)
|
||||||
|
{
|
||||||
|
this->erase(this->begin());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] size_t size() const
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
for (const auto& obj : *this)
|
||||||
|
{
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator begin()
|
||||||
|
{
|
||||||
|
return {this->entries_};
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator begin() const
|
||||||
|
{
|
||||||
|
return {this->entries_};
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator end()
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator end() const
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator erase(iterator iterator)
|
||||||
|
{
|
||||||
|
auto* list_entry = iterator.get_entry();
|
||||||
|
auto** inseration_point = &this->entries_;
|
||||||
|
while (*inseration_point && list_entry)
|
||||||
|
{
|
||||||
|
if (*inseration_point != list_entry)
|
||||||
|
{
|
||||||
|
inseration_point = &(*inseration_point)->next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
*inseration_point = list_entry->next;
|
||||||
|
|
||||||
|
list_entry->entry->~T();
|
||||||
|
this->object_allocator_.free(list_entry->entry_base);
|
||||||
|
this->list_allocator_.free(list_entry->this_base);
|
||||||
|
|
||||||
|
return iterator(*inseration_point);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::runtime_error("Bad iterator");
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend iterator;
|
||||||
|
|
||||||
|
ObjectAllocator object_allocator_{};
|
||||||
|
ListAllocator list_allocator_{};
|
||||||
|
ListEntry* entries_{nullptr};
|
||||||
|
|
||||||
|
template <typename U, typename V>
|
||||||
|
static U* align_pointer(V* pointer)
|
||||||
|
{
|
||||||
|
const auto align_bits = alignof(U) - 1;
|
||||||
|
auto ptr = reinterpret_cast<intptr_t>(pointer);
|
||||||
|
ptr = (ptr + align_bits) & (~align_bits);
|
||||||
|
|
||||||
|
return reinterpret_cast<U*>(ptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -1,12 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "type_traits.hpp"
|
#include "allocator.hpp"
|
||||||
#include "memory.hpp"
|
|
||||||
#include "exception.hpp"
|
#include "exception.hpp"
|
||||||
#include "finally.hpp"
|
#include "finally.hpp"
|
||||||
|
|
||||||
namespace utils
|
namespace utils
|
||||||
{
|
{
|
||||||
template <typename T>
|
template <typename T, typename Allocator = NonPagedAllocator>
|
||||||
|
requires IsAllocator<Allocator>
|
||||||
class vector
|
class vector
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -38,9 +38,9 @@ namespace utils
|
|||||||
this->clear();
|
this->clear();
|
||||||
this->reserve(obj.size_);
|
this->reserve(obj.size_);
|
||||||
|
|
||||||
for (size_t i = 0; i < obj.size_; ++i)
|
for (const auto& i : obj)
|
||||||
{
|
{
|
||||||
this->push_back(obj.at(i));
|
this->push_back(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,12 +75,12 @@ namespace utils
|
|||||||
auto* old_mem = this->storage_;
|
auto* old_mem = this->storage_;
|
||||||
auto* old_data = this->data();
|
auto* old_data = this->data();
|
||||||
|
|
||||||
this->storage_ = allocate_memory_for_capacity(capacity);
|
this->storage_ = this->allocate_memory_for_capacity(capacity);
|
||||||
this->capacity_ = capacity;
|
this->capacity_ = capacity;
|
||||||
|
|
||||||
auto _ = utils::finally([&old_mem]
|
auto _ = utils::finally([&old_mem, this]
|
||||||
{
|
{
|
||||||
free_memory(old_mem);
|
this->free_memory(old_mem);
|
||||||
});
|
});
|
||||||
|
|
||||||
auto* data = this->data();
|
auto* data = this->data();
|
||||||
@ -198,21 +198,41 @@ namespace utils
|
|||||||
return this->data() + this->size_;
|
return this->data() + this->size_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
T* erase(T* iterator)
|
||||||
|
{
|
||||||
|
auto index = iterator - this->begin();
|
||||||
|
if (index < 0 || static_cast<size_t>(index) > this->size_)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Bad iterator");
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto data = this->data();
|
||||||
|
for (size_t i = index + 1; i < this->size_; ++i)
|
||||||
|
{
|
||||||
|
data[i - 1] = std::move(data[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
data[this->size_--].~T();
|
||||||
|
|
||||||
|
return iterator;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Allocator allocator_{};
|
||||||
void* storage_{nullptr};
|
void* storage_{nullptr};
|
||||||
size_t capacity_{0};
|
size_t capacity_{0};
|
||||||
size_t size_{0};
|
size_t size_{0};
|
||||||
|
|
||||||
static void* allocate_memory_for_capacity(const size_t capacity)
|
void* allocate_memory_for_capacity(const size_t capacity)
|
||||||
{
|
{
|
||||||
constexpr auto alignment = alignof(T);
|
constexpr auto alignment = alignof(T);
|
||||||
auto* memory = memory::allocate_non_paged_memory(capacity * sizeof(T) + alignment);
|
auto* memory = this->allocator_.allocate(capacity * sizeof(T) + alignment);
|
||||||
return memory;
|
return memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_memory(void* memory)
|
void free_memory(void* memory)
|
||||||
{
|
{
|
||||||
memory::free_non_paged_memory(memory);
|
this->allocator_.free(memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename U>
|
template <typename U>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user