mirror of
https://github.com/usatiuk/ficus.git
synced 2025-10-29 00:27:52 +01:00
Vector and string
This commit is contained in:
13
.idea/codeStyles/Project.xml
generated
13
.idea/codeStyles/Project.xml
generated
@@ -3,5 +3,18 @@
|
||||
<clangFormatSettings>
|
||||
<option name="ENABLED" value="true" />
|
||||
</clangFormatSettings>
|
||||
<files>
|
||||
<extensions>
|
||||
<pair source="cpp" header="hpp" fileNamingConvention="NONE" />
|
||||
<pair source="c" header="h" fileNamingConvention="NONE" />
|
||||
<pair source="cu" header="cuh" fileNamingConvention="NONE" />
|
||||
<pair source="ixx" header="" fileNamingConvention="NONE" />
|
||||
<pair source="mxx" header="" fileNamingConvention="NONE" />
|
||||
<pair source="cppm" header="" fileNamingConvention="NONE" />
|
||||
<pair source="ccm" header="" fileNamingConvention="NONE" />
|
||||
<pair source="cxxm" header="" fileNamingConvention="NONE" />
|
||||
<pair source="c++m" header="" fileNamingConvention="NONE" />
|
||||
</extensions>
|
||||
</files>
|
||||
</code_scheme>
|
||||
</component>
|
||||
@@ -3,6 +3,7 @@
|
||||
//
|
||||
#include <cstddef>
|
||||
|
||||
#include "TestTemplates.hpp"
|
||||
#include "globals.hpp"
|
||||
#include "kmem.hpp"
|
||||
#include "limine_fb.hpp"
|
||||
@@ -115,24 +116,34 @@ void stress() {
|
||||
|
||||
char buf[69];
|
||||
itoa(curi, buf, 10);
|
||||
all_tty_putstr("stress ");
|
||||
all_tty_putstr(buf);
|
||||
all_tty_putstr("\n");
|
||||
remove_self();
|
||||
}
|
||||
|
||||
void templates_tester() {
|
||||
all_tty_putstr("Testing templates\n");
|
||||
test_templates();
|
||||
all_tty_putstr("Testing templates OK\n");
|
||||
|
||||
remove_self();
|
||||
}
|
||||
|
||||
void stress_tester() {
|
||||
for (int i = 0; i < 2000; i++)
|
||||
new_ktask(stress, "stress");
|
||||
|
||||
all_tty_putstr("Finished stress\n");
|
||||
|
||||
remove_self();
|
||||
}
|
||||
|
||||
void ktask_main() {
|
||||
|
||||
new_ktask(ktask, "one");
|
||||
new_ktask(freeprinter, "freeprinter");
|
||||
new_ktask(mtest1, "mtest1");
|
||||
new_ktask(mtest2, "mtest2");
|
||||
new_ktask(mtest3, "mtest3");
|
||||
|
||||
for (int i = 0; i < 2000; i++)
|
||||
new_ktask(stress, "stress");
|
||||
|
||||
all_tty_putstr("Finished stress");
|
||||
new_ktask(templates_tester, "templates_tester");
|
||||
new_ktask(stress_tester, "stress_tester");
|
||||
|
||||
remove_self();
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "serial.hpp"
|
||||
#include "task.hpp"
|
||||
|
||||
#include "string.hpp"
|
||||
#include "string.h"
|
||||
|
||||
struct HeapEntry *KERN_HeapBegin;
|
||||
uintptr_t KERN_HeapEnd;// Past the end
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "string.hpp"
|
||||
#include "string.h"
|
||||
|
||||
static volatile struct limine_framebuffer_request framebuffer_request = {
|
||||
.id = LIMINE_FRAMEBUFFER_REQUEST,
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include "kmem.hpp"
|
||||
#include "limine.h"
|
||||
#include "string.hpp"
|
||||
#include "string.h"
|
||||
|
||||
static volatile struct limine_memmap_request memmap_request = {
|
||||
.id = LIMINE_MEMMAP_REQUEST,
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include "mutex.hpp"
|
||||
#include "paging.hpp"
|
||||
#include "serial.hpp"
|
||||
#include "string.hpp"
|
||||
#include "string.h"
|
||||
#include "timer.hpp"
|
||||
#include "tty.hpp"
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
target_include_directories(kernel.elf PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
target_sources(kernel.elf PRIVATE mutex.cpp cv.cpp cppsupport.cpp Spinlock.cpp LockGuard.cpp)
|
||||
target_sources(kernel.elf PRIVATE mutex.cpp cv.cpp cppsupport.cpp Spinlock.cpp LockGuard.cpp)
|
||||
|
||||
add_subdirectory(templates)
|
||||
@@ -2,8 +2,8 @@
|
||||
// Created by Stepan Usatiuk on 21.10.2023.
|
||||
//
|
||||
|
||||
#ifndef OS2_STRING_HPP
|
||||
#define OS2_STRING_HPP
|
||||
#ifndef OS2_STRING_H
|
||||
#define OS2_STRING_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
@@ -98,4 +98,4 @@ inline void strcpy(const char *src, char *dst) {
|
||||
dst[i] = '\0';
|
||||
}
|
||||
|
||||
#endif//OS2_STRING_HPP
|
||||
#endif//OS2_STRING_H
|
||||
3
src/kernel/templates/CMakeLists.txt
Normal file
3
src/kernel/templates/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
target_include_directories(kernel.elf PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
target_sources(kernel.elf PRIVATE TestTemplates.cpp)
|
||||
25
src/kernel/templates/ListQueue.hpp
Normal file
25
src/kernel/templates/ListQueue.hpp
Normal file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// Created by Stepan Usatiuk on 21.10.2023.
|
||||
//
|
||||
|
||||
#ifndef OS2_LISTQUEUE_HPP
|
||||
#define OS2_LISTQUEUE_HPP
|
||||
|
||||
|
||||
template<typename T>
|
||||
class ListQueue {
|
||||
public:
|
||||
ListQueue() {
|
||||
}
|
||||
|
||||
private:
|
||||
struct Node {
|
||||
T val;
|
||||
Node *next;
|
||||
};
|
||||
Node *head;
|
||||
Node *tail;
|
||||
};
|
||||
|
||||
|
||||
#endif//OS2_LISTQUEUE_HPP
|
||||
108
src/kernel/templates/PointersCollection.hpp
Normal file
108
src/kernel/templates/PointersCollection.hpp
Normal file
@@ -0,0 +1,108 @@
|
||||
#ifndef POINTERS_H
|
||||
#define POINTERS_H
|
||||
|
||||
namespace SUSTL {
|
||||
class SharedPtrTester;
|
||||
|
||||
template<typename T>
|
||||
class SharedPtr {
|
||||
friend SharedPtrTester;
|
||||
public:
|
||||
SharedPtr() = default;
|
||||
|
||||
SharedPtr(T *data) : ptr(data), uses(new int(1)) {}
|
||||
|
||||
~SharedPtr() {
|
||||
if (ptr == nullptr || uses == nullptr) return;
|
||||
--(*uses);
|
||||
if (*uses == 0) {
|
||||
delete ptr;
|
||||
delete uses;
|
||||
}
|
||||
}
|
||||
|
||||
SharedPtr(SharedPtr const &other) : ptr(other.ptr), uses(other.uses) {
|
||||
++(*uses);
|
||||
}
|
||||
|
||||
SharedPtr(SharedPtr &&other) {
|
||||
uses = other.uses;
|
||||
ptr = other.ptr;
|
||||
other.uses = nullptr;
|
||||
other.ptr = nullptr;
|
||||
}
|
||||
|
||||
SharedPtr &operator=(SharedPtr other) {
|
||||
std::swap(ptr, other.ptr);
|
||||
std::swap(uses, other.uses);
|
||||
return *this;
|
||||
}
|
||||
|
||||
T *operator->() const { return ptr; }
|
||||
|
||||
T &operator*() const { return *ptr; }
|
||||
|
||||
T *get() const noexcept { return ptr; }
|
||||
|
||||
int useCount() const { return *uses; }
|
||||
|
||||
private:
|
||||
T *ptr = nullptr;
|
||||
int *uses = nullptr;
|
||||
};
|
||||
|
||||
class COWTester;
|
||||
|
||||
template<typename T>
|
||||
class COWPointer {
|
||||
private:
|
||||
friend COWTester;
|
||||
SharedPtr<T> ptr;
|
||||
|
||||
void copy() {
|
||||
if (ptr.get() && ptr.useCount() > 1) {
|
||||
ptr = SharedPtr<T>(new T(*ptr));
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
COWPointer() = default;
|
||||
|
||||
COWPointer(T *data) : ptr(data) {}
|
||||
|
||||
COWPointer(SharedPtr<T> data) : ptr(std::move(data)) {}
|
||||
|
||||
COWPointer(COWPointer &&other) = default;
|
||||
|
||||
COWPointer(COWPointer const &data) = default;
|
||||
|
||||
COWPointer &operator=(COWPointer other) {
|
||||
std::swap(ptr, other.ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~COWPointer() = default;
|
||||
|
||||
T *get() const {
|
||||
return ptr.get();
|
||||
}
|
||||
|
||||
T *getRW() {
|
||||
copy();
|
||||
return ptr.get();
|
||||
}
|
||||
|
||||
int useCount() { return ptr.useCount(); };
|
||||
|
||||
const T &operator*() const {
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
const T *operator->() const {
|
||||
return ptr.operator->();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
420
src/kernel/templates/SkipList.hpp
Normal file
420
src/kernel/templates/SkipList.hpp
Normal file
@@ -0,0 +1,420 @@
|
||||
#ifndef SKIPLIST_H
|
||||
#define SKIPLIST_H
|
||||
static bool seedSet = false;
|
||||
|
||||
class SeedSetter {
|
||||
public:
|
||||
SeedSetter() noexcept {
|
||||
if (!seedSet) {
|
||||
std::cout << "seed set!" << std::endl;
|
||||
srand(time(nullptr));// NOLINT
|
||||
seedSet = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[[maybe_unused]] static SeedSetter seedSetter;
|
||||
|
||||
template<typename K, typename V>
|
||||
class SkipList {
|
||||
static constexpr size_t maxL{31};
|
||||
friend SkipListTester;
|
||||
|
||||
public:
|
||||
struct Node {
|
||||
Node *next[maxL + 1] = {nullptr};
|
||||
Node *before = nullptr;
|
||||
bool end = false;
|
||||
K key = K();
|
||||
|
||||
V data = V();
|
||||
};
|
||||
|
||||
private:
|
||||
class NodeAllocator {
|
||||
static constexpr int size{64};
|
||||
Node *nodes[size];
|
||||
int top = -1;
|
||||
|
||||
public:
|
||||
NodeAllocator() noexcept = default;
|
||||
|
||||
~NodeAllocator() noexcept {
|
||||
for (int i = top; i >= 0; i--) {
|
||||
delete nodes[i];
|
||||
}
|
||||
}
|
||||
|
||||
void push(Node *&e) {
|
||||
if (top >= size - 1) {
|
||||
delete e;
|
||||
return;
|
||||
}
|
||||
nodes[++top] = e;
|
||||
}
|
||||
|
||||
|
||||
Node *get() {
|
||||
if (top == -1) {
|
||||
return new Node;
|
||||
}
|
||||
|
||||
Node *node = nodes[top--];
|
||||
|
||||
node->end = false;
|
||||
node->before = nullptr;
|
||||
node->next[0] = nullptr;
|
||||
node->key = K();
|
||||
// node->data = V();
|
||||
|
||||
return node;
|
||||
}
|
||||
};
|
||||
|
||||
static int randomL() {
|
||||
return ffs(rand()) - 1;// NOLINT
|
||||
}
|
||||
|
||||
static inline NodeAllocator nodeAllocator;
|
||||
|
||||
Node *root;
|
||||
Node *endnode;
|
||||
mutable Node *toUpdate[maxL + 1];
|
||||
size_t curL = 0;
|
||||
|
||||
public:
|
||||
SkipList() noexcept {
|
||||
root = (Node *) nodeAllocator.get();
|
||||
root->end = true;
|
||||
endnode = (Node *) nodeAllocator.get();
|
||||
endnode->end = true;
|
||||
endnode->before = root;
|
||||
|
||||
for (size_t i = 0; i <= maxL; i++) {
|
||||
root->next[i] = endnode;
|
||||
}
|
||||
};
|
||||
|
||||
~SkipList() noexcept {
|
||||
auto cur = root;
|
||||
while (cur != nullptr) {
|
||||
auto prev = cur;
|
||||
cur = cur->next[0];
|
||||
nodeAllocator.push(prev);
|
||||
}
|
||||
}
|
||||
|
||||
SkipList(SkipList const &l) noexcept : SkipList() {
|
||||
toUpdate[0] = root;
|
||||
|
||||
for (auto n = l.root->next[0]; n != nullptr && !n->end; n = n->next[0]) {
|
||||
size_t newLevel = randomL();
|
||||
|
||||
if (newLevel > curL) {
|
||||
for (size_t i = curL + 1; i <= newLevel; i++)
|
||||
toUpdate[i] = root;
|
||||
curL = newLevel;
|
||||
}
|
||||
|
||||
auto newNode = (Node *) nodeAllocator.get();
|
||||
newNode->key = n->key;
|
||||
newNode->data = n->data;
|
||||
newNode->before = toUpdate[0];
|
||||
if (toUpdate[0]->next[0] != nullptr) toUpdate[0]->next[0]->before = newNode;
|
||||
|
||||
for (size_t i = 0; i <= newLevel; i++) {
|
||||
newNode->next[i] = toUpdate[i]->next[i];
|
||||
toUpdate[i]->next[i] = newNode;
|
||||
toUpdate[i] = newNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SkipList(SkipList &&l) noexcept {
|
||||
this->root = l.root;
|
||||
l.root = nullptr;
|
||||
this->endnode = l.endnode;
|
||||
l.endnode = nullptr;
|
||||
this->curL = l.curL;
|
||||
l.curL = 0;
|
||||
}
|
||||
|
||||
SkipList &operator=(SkipList l) noexcept {
|
||||
std::swap(l.root, root);
|
||||
std::swap(l.endnode, endnode);
|
||||
std::swap(l.curL, curL);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void add(V *p, size_t n, bool reuseUpdate) {
|
||||
if (!reuseUpdate) {
|
||||
Node *cur = root;
|
||||
for (int i = curL; i >= 0; i--) {
|
||||
while (cur->next[i]->key < p->l && !cur->next[i]->end)
|
||||
cur = cur->next[i];
|
||||
toUpdate[i] = cur;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < n; i++, p++) {
|
||||
size_t newLevel = randomL();
|
||||
|
||||
if (newLevel > curL) {
|
||||
for (size_t j = curL + 1; j <= newLevel; j++)
|
||||
toUpdate[j] = root;
|
||||
|
||||
curL = newLevel;
|
||||
}
|
||||
|
||||
auto newNode = (Node *) nodeAllocator.get();
|
||||
newNode->key = p->l;
|
||||
newNode->data = *p;
|
||||
|
||||
newNode->before = toUpdate[0];
|
||||
if (toUpdate[0]->next[0] != nullptr) toUpdate[0]->next[0]->before = newNode;
|
||||
|
||||
for (size_t j = 0; j <= newLevel; j++) {
|
||||
newNode->next[j] = toUpdate[j]->next[j];
|
||||
toUpdate[j]->next[j] = newNode;
|
||||
toUpdate[j] = newNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool erase(Node *begin, Node *end, bool reuseUpdate) {
|
||||
if (begin == end) return false;
|
||||
|
||||
if (!reuseUpdate) {
|
||||
Node *cur = root;
|
||||
for (int i = curL; i >= 0; i--) {
|
||||
while (cur->next[i]->key < begin->key && !cur->next[i]->end)
|
||||
cur = cur->next[i];
|
||||
toUpdate[i] = cur;
|
||||
}
|
||||
}
|
||||
|
||||
Node *prev = nullptr;
|
||||
for (auto cur = begin; cur != end; cur = cur->next[0]) {
|
||||
if (prev)
|
||||
nodeAllocator.push(prev);
|
||||
|
||||
cur->next[0]->before = toUpdate[0];
|
||||
|
||||
for (size_t i = 0; i <= curL; i++) {
|
||||
if (toUpdate[i]->next[i] != cur)
|
||||
break;
|
||||
|
||||
toUpdate[i]->next[i] = cur->next[i];
|
||||
}
|
||||
|
||||
while (curL > 0 &&
|
||||
root->next[curL] == nullptr)
|
||||
curL--;
|
||||
prev = cur;
|
||||
}
|
||||
|
||||
if (prev)
|
||||
nodeAllocator.push(prev);
|
||||
return true;
|
||||
}
|
||||
|
||||
Node *add(K const &k, V const &v, bool reuseUpdate) {
|
||||
if (!reuseUpdate) {
|
||||
Node *cur = root;
|
||||
|
||||
for (int i = curL; i >= 0; i--) {
|
||||
while (cur->next[i]->key < k && !cur->next[i]->end)
|
||||
cur = cur->next[i];
|
||||
toUpdate[i] = cur;
|
||||
}
|
||||
cur = cur->next[0];
|
||||
|
||||
if (cur->key == k && !cur->end) return nullptr;
|
||||
}
|
||||
|
||||
size_t newLevel = randomL();
|
||||
|
||||
if (newLevel > curL) {
|
||||
for (size_t i = curL + 1; i <= newLevel; i++)
|
||||
toUpdate[i] = root;
|
||||
|
||||
curL = newLevel;
|
||||
}
|
||||
|
||||
auto newNode = (Node *) nodeAllocator.get();
|
||||
newNode->key = k;
|
||||
newNode->data = v;
|
||||
|
||||
newNode->before = toUpdate[0];
|
||||
if (toUpdate[0]->next[0] != nullptr) toUpdate[0]->next[0]->before = newNode;
|
||||
|
||||
for (size_t i = 0; i <= newLevel; i++) {
|
||||
newNode->next[i] = toUpdate[i]->next[i];
|
||||
toUpdate[i]->next[i] = newNode;
|
||||
toUpdate[i] = newNode;
|
||||
}
|
||||
return newNode;
|
||||
}
|
||||
|
||||
bool erase(K const &k) {
|
||||
Node *cur = root;
|
||||
|
||||
for (int i = curL; i >= 0; i--) {
|
||||
while (cur->next[i]->key < k && !cur->next[i]->end)
|
||||
cur = cur->next[i];
|
||||
toUpdate[i] = cur;
|
||||
}
|
||||
cur = cur->next[0];
|
||||
|
||||
if (cur->end || cur->key != k) return false;
|
||||
|
||||
cur->next[0]->before = toUpdate[0];
|
||||
|
||||
for (size_t i = 0; i <= curL; i++) {
|
||||
if (toUpdate[i]->next[i] != cur)
|
||||
break;
|
||||
|
||||
toUpdate[i]->next[i] = cur->next[i];
|
||||
}
|
||||
|
||||
while (curL > 0 &&
|
||||
root->next[curL] == nullptr)
|
||||
curL--;
|
||||
nodeAllocator.push(cur);
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
// Returns the node PRECEDING the node with a key that is GREATER than k
|
||||
Node *find(K const &k) const {
|
||||
Node *cur = root;
|
||||
|
||||
for (int i = curL; i >= 0; i--)
|
||||
while (cur->next[i]->key <= k && !cur->next[i]->end)
|
||||
cur = cur->next[i];
|
||||
|
||||
return cur;
|
||||
}
|
||||
|
||||
Node *upper_bound(K const &k) const {
|
||||
Node *cur = root;
|
||||
|
||||
for (int i = curL; i >= 0; i--) {
|
||||
while (cur->next[i]->key <= k && !cur->next[i]->end)
|
||||
cur = cur->next[i];
|
||||
}
|
||||
|
||||
cur = cur->next[0];
|
||||
|
||||
return cur;
|
||||
}
|
||||
|
||||
Node *lower_bound_update(K const &k) const {
|
||||
Node *cur = root;
|
||||
|
||||
for (int i = curL; i >= 0; i--) {
|
||||
while (cur->next[i]->key < k && !cur->next[i]->end)
|
||||
cur = cur->next[i];
|
||||
toUpdate[i] = cur;
|
||||
}
|
||||
|
||||
cur = cur->next[0];
|
||||
|
||||
return cur;
|
||||
}
|
||||
|
||||
|
||||
Node *lower_bound(K const &k) const {
|
||||
Node *cur = root;
|
||||
|
||||
for (int i = curL; i >= 0; i--) {
|
||||
while (cur->next[i]->key < k && !cur->next[i]->end)
|
||||
cur = cur->next[i];
|
||||
}
|
||||
|
||||
cur = cur->next[0];
|
||||
|
||||
return cur;
|
||||
}
|
||||
|
||||
|
||||
bool operator==(SkipList const &r) const {
|
||||
auto n = root->next[0];
|
||||
auto n2 = r.root->next[0];
|
||||
|
||||
while (!n->end && !n2->end) {
|
||||
if (!(n->data == n2->data)) return false;
|
||||
n = n->next[0];
|
||||
n2 = n2->next[0];
|
||||
}
|
||||
|
||||
if ((n->end || n2->end) && n->end != n2->end) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
struct SkipListIterator {
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = const V;
|
||||
using pointer = value_type *;
|
||||
using reference = value_type &;
|
||||
|
||||
explicit SkipListIterator(Node *n) : n(std::move(n)){};
|
||||
|
||||
reference operator*() const { return n->data; }
|
||||
|
||||
pointer operator->() const { return &(n->data); }
|
||||
|
||||
SkipListIterator &operator--() {
|
||||
if (!n->end)
|
||||
n = n->before;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SkipListIterator &operator++() {
|
||||
if (!n->end)
|
||||
n = n->next[0];
|
||||
return *this;
|
||||
}
|
||||
|
||||
SkipListIterator operator++(int) {
|
||||
SkipListIterator tmp = *this;
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
friend bool operator==(const SkipListIterator &a, const SkipListIterator &b) { return a.n == b.n; };
|
||||
|
||||
friend bool operator!=(const SkipListIterator &a, const SkipListIterator &b) { return a.n != b.n; };
|
||||
|
||||
private:
|
||||
Node *n;
|
||||
};
|
||||
|
||||
// using iterator = SkipListIterator;
|
||||
using const_iterator = SkipListIterator;
|
||||
|
||||
const_iterator begin() const { return SkipListIterator(root->next[0]); }
|
||||
|
||||
const_iterator end() const { return SkipListIterator(endnode); }
|
||||
|
||||
void print() const {
|
||||
std::cout << "LIST STATUS" << std::endl;
|
||||
|
||||
for (size_t i = 0; i <= curL; i++) {
|
||||
Node *n = root->next[i];
|
||||
std::cout << "L " << i << ": ";
|
||||
while (n != nullptr && n->next[0]) {
|
||||
std::cout << "GUARD: " << n->end << " KEY: " << n->key << " RANGE: " << n->data
|
||||
<< " <<<<<";
|
||||
n = n->next[i];
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
321
src/kernel/templates/SkipListSet.hpp
Normal file
321
src/kernel/templates/SkipListSet.hpp
Normal file
@@ -0,0 +1,321 @@
|
||||
#ifndef SkipListSetSET_H
|
||||
#define SkipListSetSET_H
|
||||
|
||||
template<typename K>
|
||||
class SkipListSet {
|
||||
static constexpr size_t maxL{31};
|
||||
friend SkipListSetTester;
|
||||
|
||||
public:
|
||||
struct Node {
|
||||
Node *next[maxL + 1] = {nullptr};
|
||||
Node *before = nullptr;
|
||||
bool end = false;
|
||||
K key = K();
|
||||
};
|
||||
|
||||
private:
|
||||
class NodeAllocator {
|
||||
static constexpr int size{64};
|
||||
Node *nodes[size];
|
||||
int top = -1;
|
||||
|
||||
public:
|
||||
NodeAllocator() noexcept = default;
|
||||
|
||||
~NodeAllocator() noexcept {
|
||||
for (int i = top; i >= 0; i--) {
|
||||
delete nodes[i];
|
||||
}
|
||||
}
|
||||
|
||||
void push(Node *&e) {
|
||||
if (top >= size - 1) {
|
||||
delete e;
|
||||
return;
|
||||
}
|
||||
nodes[++top] = e;
|
||||
}
|
||||
|
||||
|
||||
Node *get() {
|
||||
if (top == -1) {
|
||||
return new Node;
|
||||
}
|
||||
|
||||
Node *node = nodes[top--];
|
||||
|
||||
node->end = false;
|
||||
node->before = nullptr;
|
||||
node->next[0] = nullptr;
|
||||
node->key = K();
|
||||
// node->data = V();
|
||||
|
||||
return node;
|
||||
}
|
||||
};
|
||||
|
||||
static int randomL() {
|
||||
return ffs(rand()) - 1;// NOLINT
|
||||
}
|
||||
|
||||
static inline NodeAllocator nodeAllocator;
|
||||
|
||||
Node *root;
|
||||
Node *endnode;
|
||||
mutable Node *toUpdate[maxL + 1];
|
||||
size_t curL = 0;
|
||||
|
||||
public:
|
||||
SkipListSet() noexcept {
|
||||
root = (Node *) nodeAllocator.get();
|
||||
root->end = true;
|
||||
endnode = (Node *) nodeAllocator.get();
|
||||
endnode->end = true;
|
||||
endnode->before = root;
|
||||
|
||||
for (size_t i = 0; i <= maxL; i++) {
|
||||
root->next[i] = endnode;
|
||||
}
|
||||
};
|
||||
|
||||
~SkipListSet() noexcept {
|
||||
auto cur = root;
|
||||
while (cur != nullptr) {
|
||||
auto prev = cur;
|
||||
cur = cur->next[0];
|
||||
nodeAllocator.push(prev);
|
||||
}
|
||||
}
|
||||
|
||||
SkipListSet(SkipListSet const &l) noexcept : SkipListSet() {
|
||||
toUpdate[0] = root;
|
||||
|
||||
for (auto n = l.root->next[0]; n != nullptr && !n->end; n = n->next[0]) {
|
||||
size_t newLevel = randomL();
|
||||
|
||||
if (newLevel > curL) {
|
||||
for (size_t i = curL + 1; i <= newLevel; i++)
|
||||
toUpdate[i] = root;
|
||||
curL = newLevel;
|
||||
}
|
||||
|
||||
auto newNode = (Node *) nodeAllocator.get();
|
||||
newNode->key = n->key;
|
||||
newNode->data = n->data;
|
||||
newNode->before = toUpdate[0];
|
||||
if (toUpdate[0]->next[0] != nullptr) toUpdate[0]->next[0]->before = newNode;
|
||||
|
||||
for (size_t i = 0; i <= newLevel; i++) {
|
||||
newNode->next[i] = toUpdate[i]->next[i];
|
||||
toUpdate[i]->next[i] = newNode;
|
||||
toUpdate[i] = newNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SkipListSet(SkipListSet &&l) noexcept {
|
||||
this->root = l.root;
|
||||
l.root = nullptr;
|
||||
this->endnode = l.endnode;
|
||||
l.endnode = nullptr;
|
||||
this->curL = l.curL;
|
||||
l.curL = 0;
|
||||
}
|
||||
|
||||
SkipListSet &operator=(SkipListSet l) noexcept {
|
||||
std::swap(l.root, root);
|
||||
std::swap(l.endnode, endnode);
|
||||
std::swap(l.curL, curL);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool erase(Node *begin, Node *end, bool reuseUpdate) {
|
||||
if (begin == end) return false;
|
||||
|
||||
if (!reuseUpdate) {
|
||||
Node *cur = root;
|
||||
for (int i = curL; i >= 0; i--) {
|
||||
while (cur->next[i]->key < begin->key && !cur->next[i]->end)
|
||||
cur = cur->next[i];
|
||||
toUpdate[i] = cur;
|
||||
}
|
||||
}
|
||||
|
||||
Node *prev = nullptr;
|
||||
for (auto cur = begin; cur != end; cur = cur->next[0]) {
|
||||
if (prev)
|
||||
nodeAllocator.push(prev);
|
||||
|
||||
cur->next[0]->before = toUpdate[0];
|
||||
|
||||
for (size_t i = 0; i <= curL; i++) {
|
||||
if (toUpdate[i]->next[i] != cur)
|
||||
break;
|
||||
|
||||
toUpdate[i]->next[i] = cur->next[i];
|
||||
}
|
||||
|
||||
while (curL > 0 &&
|
||||
root->next[curL] == nullptr)
|
||||
curL--;
|
||||
prev = cur;
|
||||
}
|
||||
|
||||
if (prev)
|
||||
nodeAllocator.push(prev);
|
||||
return true;
|
||||
}
|
||||
|
||||
Node *add(K const &k, bool reuseUpdate) {
|
||||
if (!reuseUpdate) {
|
||||
Node *cur = root;
|
||||
|
||||
for (int i = curL; i >= 0; i--) {
|
||||
while (cur->next[i]->key < k && !cur->next[i]->end)
|
||||
cur = cur->next[i];
|
||||
toUpdate[i] = cur;
|
||||
}
|
||||
cur = cur->next[0];
|
||||
|
||||
if (cur->key == k) return nullptr;
|
||||
}
|
||||
|
||||
size_t newLevel = randomL();
|
||||
|
||||
if (newLevel > curL) {
|
||||
for (size_t i = curL + 1; i <= newLevel; i++)
|
||||
toUpdate[i] = root;
|
||||
|
||||
curL = newLevel;
|
||||
}
|
||||
|
||||
auto newNode = (Node *) nodeAllocator.get();
|
||||
newNode->key = k;
|
||||
|
||||
newNode->before = toUpdate[0];
|
||||
if (toUpdate[0]->next[0] != nullptr) toUpdate[0]->next[0]->before = newNode;
|
||||
|
||||
for (size_t i = 0; i <= newLevel; i++) {
|
||||
newNode->next[i] = toUpdate[i]->next[i];
|
||||
toUpdate[i]->next[i] = newNode;
|
||||
toUpdate[i] = newNode;
|
||||
}
|
||||
return newNode;
|
||||
}
|
||||
|
||||
bool erase(K const &k) {
|
||||
Node *cur = root;
|
||||
|
||||
for (int i = curL; i >= 0; i--) {
|
||||
while (cur->next[i]->key < k && !cur->next[i]->end)
|
||||
cur = cur->next[i];
|
||||
toUpdate[i] = cur;
|
||||
}
|
||||
cur = cur->next[0];
|
||||
|
||||
if (cur->end || cur->key != k) return false;
|
||||
|
||||
cur->next[0]->before = toUpdate[0];
|
||||
|
||||
for (size_t i = 0; i <= curL; i++) {
|
||||
if (toUpdate[i]->next[i] != cur)
|
||||
break;
|
||||
|
||||
toUpdate[i]->next[i] = cur->next[i];
|
||||
}
|
||||
|
||||
while (curL > 0 &&
|
||||
root->next[curL] == nullptr)
|
||||
curL--;
|
||||
nodeAllocator.push(cur);
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
// Returns the node PRECEDING the node with a key that is GREATER than k
|
||||
Node *find(K const &k) const {
|
||||
Node *cur = root;
|
||||
|
||||
for (int i = curL; i >= 0; i--)
|
||||
while (cur->next[i]->key <= k && !cur->next[i]->end)
|
||||
cur = cur->next[i];
|
||||
|
||||
return cur;
|
||||
}
|
||||
|
||||
Node *upper_bound(K const &k) const {
|
||||
Node *cur = root;
|
||||
|
||||
for (int i = curL; i >= 0; i--) {
|
||||
while (cur->next[i]->key <= k && !cur->next[i]->end)
|
||||
cur = cur->next[i];
|
||||
}
|
||||
|
||||
cur = cur->next[0];
|
||||
|
||||
return cur;
|
||||
}
|
||||
|
||||
Node *lower_bound_update(K const &k) const {
|
||||
Node *cur = root;
|
||||
|
||||
for (int i = curL; i >= 0; i--) {
|
||||
while (cur->next[i]->key < k && !cur->next[i]->end)
|
||||
cur = cur->next[i];
|
||||
toUpdate[i] = cur;
|
||||
}
|
||||
|
||||
cur = cur->next[0];
|
||||
|
||||
return cur;
|
||||
}
|
||||
|
||||
|
||||
Node *lower_bound(K const &k) const {
|
||||
Node *cur = root;
|
||||
|
||||
for (int i = curL; i >= 0; i--) {
|
||||
while (cur->next[i]->key < k && !cur->next[i]->end)
|
||||
cur = cur->next[i];
|
||||
}
|
||||
|
||||
cur = cur->next[0];
|
||||
|
||||
return cur;
|
||||
}
|
||||
|
||||
|
||||
bool operator==(SkipListSet const &r) const {
|
||||
auto n = root->next[0];
|
||||
auto n2 = r.root->next[0];
|
||||
|
||||
while (!n->end && !n2->end) {
|
||||
if (!(n->data == n2->data)) return false;
|
||||
n = n->next[0];
|
||||
n2 = n2->next[0];
|
||||
}
|
||||
|
||||
if ((n->end || n2->end) && n->end != n2->end) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void print() const {
|
||||
std::cout << "LIST STATUS" << std::endl;
|
||||
|
||||
for (size_t i = 0; i <= curL; i++) {
|
||||
Node *n = root->next[i];
|
||||
std::cout << "L " << i << ": ";
|
||||
while (n != nullptr && n->next[0]) {
|
||||
std::cout << "GUARD: " << n->end << " KEY: " << n->key << " RANGE: " << n->data
|
||||
<< " <<<<<";
|
||||
n = n->next[i];
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
90
src/kernel/templates/String.hpp
Normal file
90
src/kernel/templates/String.hpp
Normal file
@@ -0,0 +1,90 @@
|
||||
#ifndef STRING_H
|
||||
#define STRING_H
|
||||
|
||||
#include <cstdlib>
|
||||
#include <utility>
|
||||
|
||||
#include "kmem.hpp"
|
||||
#include "serial.hpp"
|
||||
#include "string.h"
|
||||
|
||||
class String {
|
||||
public:
|
||||
String() noexcept {
|
||||
data = static_cast<char *>(kmalloc(1 * sizeof(char)));
|
||||
data[0] = '\0';
|
||||
}
|
||||
|
||||
String(const char *in) noexcept {
|
||||
unsigned int curLen = strlen(in);
|
||||
|
||||
data = static_cast<char *>(kmalloc((curLen + 1) * sizeof(char)));
|
||||
data[0] = '\0';
|
||||
|
||||
strcat(data, in);
|
||||
}
|
||||
|
||||
String(String const &str) noexcept {
|
||||
unsigned int curLen = strlen(str.data);
|
||||
|
||||
data = static_cast<char *>(kmalloc((curLen + 1) * sizeof(char)));
|
||||
data[0] = '\0';
|
||||
|
||||
strcat(data, str.data);
|
||||
}
|
||||
|
||||
String(String &&str) noexcept {
|
||||
data = str.data;
|
||||
str.data = nullptr;
|
||||
}
|
||||
|
||||
String &operator=(String str) noexcept {
|
||||
std::swap(data, str.data);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~String() noexcept {
|
||||
if (data == nullptr) return;
|
||||
kfree(data);
|
||||
data = nullptr;
|
||||
}
|
||||
|
||||
String &operator+=(String const &rhs) {
|
||||
data = static_cast<char *>(krealloc(data, sizeof(char) * (strlen(data) + strlen(rhs.data) + 1)));
|
||||
assert(data != nullptr);
|
||||
|
||||
strcat(data, rhs.data);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const char *c_str() {
|
||||
return data;
|
||||
}
|
||||
|
||||
bool operator==(String const &rhs) const {
|
||||
return strcmp(data, rhs.data) == 0;
|
||||
}
|
||||
|
||||
bool operator!=(String const &rhs) const {
|
||||
return strcmp(data, rhs.data) != 0;
|
||||
}
|
||||
|
||||
bool operator<(String const &rhs) const {
|
||||
return strcmp(data, rhs.data) < 0;
|
||||
}
|
||||
|
||||
bool operator<=(String const &rhs) const {
|
||||
return strcmp(data, rhs.data) <= 0;
|
||||
}
|
||||
|
||||
bool operator>(String const &rhs) const {
|
||||
return strcmp(data, rhs.data) > 0;
|
||||
}
|
||||
|
||||
private:
|
||||
// unsigned int curLen = 0;
|
||||
char *data;
|
||||
};
|
||||
|
||||
#endif
|
||||
191
src/kernel/templates/TestTemplates.cpp
Normal file
191
src/kernel/templates/TestTemplates.cpp
Normal file
@@ -0,0 +1,191 @@
|
||||
//
|
||||
// Created by Stepan Usatiuk on 21.10.2023.
|
||||
//
|
||||
|
||||
#include "TestTemplates.hpp"
|
||||
|
||||
|
||||
#include "String.hpp"
|
||||
#include "Vector.hpp"
|
||||
#include "serial.hpp"
|
||||
|
||||
//#include "String.hpp"
|
||||
//#include "String.hpp"
|
||||
|
||||
//template<typename T>
|
||||
//std::string toString(const T &x) {
|
||||
// std::ostringstream oss;
|
||||
// oss << x;
|
||||
// return oss.str();
|
||||
//}
|
||||
//
|
||||
//class SharedPtrTester {
|
||||
//private:
|
||||
// auto getThingy() {
|
||||
// return SharedPtr<Vector<String>>(
|
||||
// new Vector<String>{"Thingy1", "Thingy2", "Thingy3"});
|
||||
// }
|
||||
//
|
||||
//public:
|
||||
// bool test() {
|
||||
// SharedPtr<Vector<String>> test1(
|
||||
// new Vector<String>{"hello1", "hello2", "hello3"});
|
||||
// SharedPtr<Vector<String>> test2(getThingy());
|
||||
// assert((*test2 == Vector<String>{"Thingy1", "Thingy2", "Thingy3"}));
|
||||
// auto test22 = test2;
|
||||
// auto test12 = test1;
|
||||
// test12->emplace_back("hello4");
|
||||
// assert((*test1)[3] == "hello4");
|
||||
// test22->erase(2);
|
||||
// assert(test2->size() == 2);
|
||||
// assert((*test2)[1] == "Thingy2");
|
||||
// return true;
|
||||
// }
|
||||
//};
|
||||
//
|
||||
//class COWTester {
|
||||
//private:
|
||||
// auto getThingy() const {
|
||||
// return COWPointer<Vector<String>>(
|
||||
// new Vector<String>{"Thingy1", "Thingy2", "Thingy3"});
|
||||
// }
|
||||
//
|
||||
//public:
|
||||
// bool test() const {
|
||||
// COWPointer<Vector<String>> test1(
|
||||
// new Vector<String>{"hello1", "hello2", "hello3"});
|
||||
// COWPointer<Vector<String>> test2(getThingy());
|
||||
// assert((*test2.get() == Vector<String>{"Thingy1", "Thingy2", "Thingy3"}));
|
||||
//
|
||||
// auto test22 = test2;
|
||||
// auto test12 = test1;
|
||||
//
|
||||
// assert(test12.ptr.get() == test1.ptr.get());
|
||||
// assert(test22.ptr.get() == test2.ptr.get());
|
||||
// assert((*test2.get() == Vector<String>{"Thingy1", "Thingy2", "Thingy3"}));
|
||||
// assert((*test22.get() == Vector<String>{"Thingy1", "Thingy2", "Thingy3"}));
|
||||
// assert((*test1.get() == Vector<String>{"hello1", "hello2", "hello3"}));
|
||||
// assert((*test12.get() == Vector<String>{"hello1", "hello2", "hello3"}));
|
||||
// assert(test12.ptr.get() == test1.ptr.get());
|
||||
// assert(test22.ptr.get() == test2.ptr.get());
|
||||
//
|
||||
// test12.getRW()->emplace_back("hello4");
|
||||
// assert(test1.get()->size() == 3);
|
||||
// assert(test12.get()->size() == 4);
|
||||
// assert((*test12.get())[3] == "hello4");
|
||||
// test22.getRW()->erase(2);
|
||||
// assert(test2.get()->size() == 3);
|
||||
// assert(test22.get()->size() == 2);
|
||||
// assert((*test22.get())[1] == "Thingy2");
|
||||
// assert((*test2.get())[1] == "Thingy2");
|
||||
//
|
||||
// assert(test12.ptr.get() != test1.ptr.get());
|
||||
// assert(test22.ptr.get() != test2.ptr.get());
|
||||
//
|
||||
// return true;
|
||||
// }
|
||||
//};
|
||||
|
||||
class VectorTester {
|
||||
public:
|
||||
bool test() {
|
||||
Vector<String> testv1;
|
||||
testv1.emplace_back("H1");
|
||||
testv1.emplace_back("H2");
|
||||
testv1.emplace_back("H3");
|
||||
testv1.emplace_back("H4");
|
||||
assert(testv1.size() == 4);
|
||||
assert(testv1.capacity >= 4);
|
||||
assert(testv1[0] == "H1");
|
||||
assert(testv1[1] == "H2");
|
||||
assert(testv1[2] == "H3");
|
||||
assert(testv1[3] == "H4");
|
||||
testv1.erase(1);
|
||||
assert(testv1.size() == 3);
|
||||
assert(testv1[0] == "H1");
|
||||
assert(testv1[1] == "H3");
|
||||
assert(testv1[3] == "H4");
|
||||
testv1.erase(1);
|
||||
assert(testv1.size() == 2);
|
||||
assert(testv1[0] == "H1");
|
||||
assert(testv1[1] == "H4");
|
||||
|
||||
testv1.emplace_back("H5");
|
||||
|
||||
auto testv2 = testv1;
|
||||
assert(testv1 == testv2);
|
||||
testv1.erase(2);
|
||||
assert(testv1 != testv2);
|
||||
testv1.emplace_back("H6");
|
||||
assert(testv1 != testv2);
|
||||
assert(testv1[2] == "H6");
|
||||
assert(testv2[2] == "H5");
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class StringTester {
|
||||
public:
|
||||
bool test() {
|
||||
String str1("hello");
|
||||
assert(str1 == "hello");
|
||||
str1 += "Hello!";
|
||||
assert(str1 == "helloHello!");
|
||||
str1 = String("abcd");
|
||||
String str2("dcba");
|
||||
assert(str2 > str1);
|
||||
assert(str1 < str2);
|
||||
assert(str1 <= str2);
|
||||
str2 = "abcd";
|
||||
assert(str1 <= str2);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
//class SkipListTester {
|
||||
//public:
|
||||
// bool test() {
|
||||
// SkipList<int, std::string> test1;
|
||||
//
|
||||
// test1.add(5, "test5", false);
|
||||
// test1.add(999, "test999", false);
|
||||
// test1.add(5, "test5", false);
|
||||
// test1.add(1, "test1", false);
|
||||
// test1.add(999, "test999", false);
|
||||
//
|
||||
// assert(test1.find(5)->data == "test5");
|
||||
// assert(test1.find(1)->data == "test1");
|
||||
// assert(test1.find(999)->data == "test999");
|
||||
//
|
||||
// test1.erase(1);
|
||||
// assert(test1.find(1)->data != "test1");
|
||||
// test1.add(87, "test87", false);
|
||||
// assert(test1.find(87)->data == "test87");
|
||||
//
|
||||
// auto p2 = test1.lower_bound_update(78);
|
||||
// assert(p2->data == "test87");
|
||||
// test1.add(78, "test78", true);
|
||||
// assert(test1.find(78)->data == "test78");
|
||||
//
|
||||
// assert(IT::test());
|
||||
//
|
||||
// return true;
|
||||
// }
|
||||
//};
|
||||
//
|
||||
int test_templates() {
|
||||
|
||||
// SkipListTester SLTester;
|
||||
// SLTester.test();
|
||||
StringTester stringTester;
|
||||
stringTester.test();
|
||||
VectorTester vectorTester;
|
||||
vectorTester.test();
|
||||
// SharedPtrTester sharedPtrTester;
|
||||
// sharedPtrTester.test();
|
||||
// COWTester cowTester;
|
||||
// cowTester.test();
|
||||
return 0;
|
||||
}
|
||||
10
src/kernel/templates/TestTemplates.hpp
Normal file
10
src/kernel/templates/TestTemplates.hpp
Normal file
@@ -0,0 +1,10 @@
|
||||
//
|
||||
// Created by Stepan Usatiuk on 21.10.2023.
|
||||
//
|
||||
|
||||
#ifndef OS2_TESTTEMPLATES_HPP
|
||||
#define OS2_TESTTEMPLATES_HPP
|
||||
|
||||
int test_templates();
|
||||
|
||||
#endif//OS2_TESTTEMPLATES_HPP
|
||||
125
src/kernel/templates/Vector.hpp
Normal file
125
src/kernel/templates/Vector.hpp
Normal file
@@ -0,0 +1,125 @@
|
||||
#ifndef VECTOR_H
|
||||
#define VECTOR_H
|
||||
|
||||
#include <new>
|
||||
|
||||
#include "kmem.hpp"
|
||||
#include "serial.hpp"
|
||||
#include "string.h"
|
||||
|
||||
class VectorTester;
|
||||
|
||||
template<typename T>
|
||||
class Vector {
|
||||
friend VectorTester;
|
||||
|
||||
public:
|
||||
Vector() noexcept {
|
||||
data = static_cast<T *>(kmalloc(capacity * sizeof(T)));
|
||||
}
|
||||
|
||||
Vector(std::initializer_list<T> l) noexcept {
|
||||
curSize = l.size();
|
||||
capacity = curSize > 0 ? curSize : 2;
|
||||
|
||||
data = static_cast<T *>(kmalloc(capacity * sizeof(T)));
|
||||
|
||||
size_t i = 0;
|
||||
for (auto const &el: l) {
|
||||
new (data + (i++)) T(el);
|
||||
}
|
||||
}
|
||||
|
||||
Vector(Vector const &vec) noexcept {
|
||||
curSize = vec.curSize;
|
||||
capacity = curSize > 0 ? curSize : 2;
|
||||
|
||||
data = static_cast<T *>(kmalloc(capacity * sizeof(T)));
|
||||
|
||||
for (size_t i = 0; i < curSize; i++)
|
||||
new (data + i) T(vec.data[i]);
|
||||
}
|
||||
|
||||
Vector(Vector &&v) noexcept {
|
||||
curSize = v.curSize;
|
||||
capacity = v.capacity;
|
||||
data = v.data;
|
||||
v.data = nullptr;
|
||||
}
|
||||
|
||||
Vector &operator=(Vector vec) noexcept {
|
||||
std::swap(vec.data, data);
|
||||
std::swap(vec.curSize, curSize);
|
||||
std::swap(vec.capacity, capacity);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~Vector() noexcept {
|
||||
if (data == nullptr) return;
|
||||
if constexpr (!std::is_trivially_destructible<T>::value)
|
||||
for (size_t i = 0; i < curSize; i++) data[i].~T();
|
||||
kfree(data);
|
||||
data = nullptr;
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
void emplace_back(Args &&...args) {
|
||||
if (capacity == curSize) {
|
||||
capacity *= 2;
|
||||
//Ugly hack to get around g++ warnings
|
||||
data = (T *) krealloc(reinterpret_cast<char *>(data), capacity * sizeof(T));
|
||||
assert(data != nullptr);
|
||||
}
|
||||
new (data + (curSize++)) T(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
void compact() {
|
||||
data = (T *) krealloc(reinterpret_cast<char *>(data), curSize * sizeof(T));
|
||||
capacity = curSize;
|
||||
}
|
||||
|
||||
void erase(size_t idx) {
|
||||
if constexpr (!std::is_trivially_destructible<T>::value)
|
||||
(data + idx)->~T();
|
||||
//Ugly hack to get around g++ warnings
|
||||
memmove(reinterpret_cast<char *>(data + idx), reinterpret_cast<char *>(data + idx + 1),
|
||||
sizeof(T) * (curSize - idx - 1));
|
||||
|
||||
curSize--;
|
||||
}
|
||||
|
||||
T &operator[](size_t idx) {
|
||||
return data[idx];
|
||||
}
|
||||
|
||||
T const &operator[](size_t idx) const {
|
||||
return data[idx];
|
||||
}
|
||||
|
||||
bool operator==(Vector const &rhs) const {
|
||||
if (curSize != rhs.curSize) return false;
|
||||
else
|
||||
for (size_t i = 0; i < curSize; i++)
|
||||
if (data[i] != rhs.data[i]) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator!=(Vector const &rhs) const {
|
||||
if (curSize != rhs.curSize) return true;
|
||||
else
|
||||
for (size_t i = 0; i < curSize; i++)
|
||||
if (data[i] != rhs.data[i]) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return curSize;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t capacity = 2;
|
||||
size_t curSize = 0;
|
||||
T *data;
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user