Reformat
This commit is contained in:
@ -91,7 +91,7 @@ bool VESA::initGraphicMode(uint16_t mode) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Kernel::kout << "TotalVideoMemory: " << ((ib->TotalMemory*65536) / (1024*1024)) << " MB" << endl;
|
// Util::System::out << "TotalVideoMemory: " << ((ib->TotalMemory*65536) / (1024*1024)) << " MB" << endl;
|
||||||
|
|
||||||
// Gewuenschten Grafikmodus aus Antwort suchen
|
// Gewuenschten Grafikmodus aus Antwort suchen
|
||||||
auto *modePtr = reinterpret_cast<uint16_t *>((ib->VideoModePtr[1] << 4) + ib->VideoModePtr[0]);
|
auto *modePtr = reinterpret_cast<uint16_t *>((ib->VideoModePtr[1] << 4) + ib->VideoModePtr[0]);
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
*---------------------------------------------------------------------------*
|
*---------------------------------------------------------------------------*
|
||||||
* Beschreibung: Ein Bluescreen, falls eine x86 Exception auftritt. Evt. *
|
* Beschreibung: Ein Bluescreen, falls eine x86 Exception auftritt. Evt. *
|
||||||
* ist der Stack und oder Heap kaputt, weswegen hier nicht *
|
* ist der Stack und oder Heap kaputt, weswegen hier nicht *
|
||||||
* Kernel::kout etc. verwendet wird. *
|
* Util::System::out etc. verwendet wird. *
|
||||||
* *
|
* *
|
||||||
* Autor: Michael Schoettner, 11.12.2018 *
|
* Autor: Michael Schoettner, 11.12.2018 *
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
*---------------------------------------------------------------------------*
|
*---------------------------------------------------------------------------*
|
||||||
* Beschreibung: Ein Bluescreen, falls eine x86 Exception auftritt. Evt. *
|
* Beschreibung: Ein Bluescreen, falls eine x86 Exception auftritt. Evt. *
|
||||||
* ist der Stack und oder Heap kaputt, weswegen hier nicht *
|
* ist der Stack und oder Heap kaputt, weswegen hier nicht *
|
||||||
* Kernel::kout etc. verwendet wird. *
|
* Util::System::out etc. verwendet wird. *
|
||||||
* *
|
* *
|
||||||
* Autor: Michael Schoettner, 2.2.2017 *
|
* Autor: Michael Schoettner, 2.2.2017 *
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|||||||
@ -31,7 +31,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// Kernel::kout << "Idle!" << endl;
|
// Util::System::out << "Idle!" << endl;
|
||||||
scheduler.yield();
|
scheduler.yield();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,14 +29,6 @@ namespace Kernel {
|
|||||||
|
|
||||||
constexpr const bool INSANE_TRACE = false;
|
constexpr const bool INSANE_TRACE = false;
|
||||||
|
|
||||||
/*****************************************************************************
|
|
||||||
* Methode: Dispatcher::dispatch *
|
|
||||||
*---------------------------------------------------------------------------*
|
|
||||||
* Beschreibung: Auf den active thread wechseln. *
|
|
||||||
* *
|
|
||||||
* Parameter: *
|
|
||||||
* next Thread der die CPU::erhalten soll. *
|
|
||||||
*****************************************************************************/
|
|
||||||
void Scheduler::start(Container::Vector<Memory::unique_ptr<Thread>>::iterator next) {
|
void Scheduler::start(Container::Vector<Memory::unique_ptr<Thread>>::iterator next) {
|
||||||
active = next;
|
active = next;
|
||||||
if (active >= ready_queue.end()) {
|
if (active >= ready_queue.end()) {
|
||||||
@ -139,7 +131,8 @@ void Scheduler::kill(uint32_t tid, Memory::unique_ptr<Thread> *ptr) {
|
|||||||
uint32_t prev_tid = (*active)->tid;
|
uint32_t prev_tid = (*active)->tid;
|
||||||
|
|
||||||
// Block queue, can always kill
|
// Block queue, can always kill
|
||||||
for (Container::Vector<Memory::unique_ptr<Thread>>::iterator it = block_queue.begin(); it != block_queue.end(); ++it) {
|
for (Container::Vector<Memory::unique_ptr<Thread>>::iterator it = block_queue.begin();
|
||||||
|
it != block_queue.end(); ++it) {
|
||||||
if ((*it)->tid == tid) {
|
if ((*it)->tid == tid) {
|
||||||
// Found thread to kill
|
// Found thread to kill
|
||||||
|
|
||||||
@ -165,7 +158,8 @@ void Scheduler::kill(uint32_t tid, Memory::unique_ptr<Thread> *ptr) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Container::Vector<Memory::unique_ptr<Thread>>::iterator it = ready_queue.begin(); it != ready_queue.end(); ++it) {
|
for (Container::Vector<Memory::unique_ptr<Thread>>::iterator it = ready_queue.begin();
|
||||||
|
it != ready_queue.end(); ++it) {
|
||||||
if ((*it)->tid == tid) {
|
if ((*it)->tid == tid) {
|
||||||
// Found thread to kill
|
// Found thread to kill
|
||||||
|
|
||||||
@ -322,7 +316,8 @@ void Scheduler::deblock(uint32_t tid) {
|
|||||||
|
|
||||||
Device::CPU::disable_int();
|
Device::CPU::disable_int();
|
||||||
|
|
||||||
for (Container::Vector<Memory::unique_ptr<Thread>>::iterator it = block_queue.begin(); it != block_queue.end(); ++it) {
|
for (Container::Vector<Memory::unique_ptr<Thread>>::iterator it = block_queue.begin();
|
||||||
|
it != block_queue.end(); ++it) {
|
||||||
if ((*it)->tid == tid) {
|
if ((*it)->tid == tid) {
|
||||||
// Found thread with correct tid
|
// Found thread with correct tid
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
#define Scheduler_include__
|
#define Scheduler_include__
|
||||||
|
|
||||||
#include "Thread.h"
|
#include "Thread.h"
|
||||||
#include "lib/mem/UniquePointer.h"
|
#include "lib/memory/UniquePointer.h"
|
||||||
#include "lib/stream/Logger.h"
|
#include "lib/stream/Logger.h"
|
||||||
#include "lib/container/Vector.h"
|
#include "lib/container/Vector.h"
|
||||||
|
|
||||||
@ -26,17 +26,20 @@ private:
|
|||||||
Container::Vector<Memory::unique_ptr<Thread>> ready_queue;
|
Container::Vector<Memory::unique_ptr<Thread>> ready_queue;
|
||||||
Container::Vector<Memory::unique_ptr<Thread>> block_queue;
|
Container::Vector<Memory::unique_ptr<Thread>> block_queue;
|
||||||
|
|
||||||
// NOTE: It makes sense to keep track of the active thread through this as it makes handling the
|
// It makes sense to keep track of the active thread through this as it makes handling the
|
||||||
// unique_ptr easier and reduces the copying in the vector when cycling through the threads
|
// unique_ptr easier and reduces the copying in the vector when cycling through the threads
|
||||||
|
// as we don't have to keep the active thread at the front (would only make sense with a queue)
|
||||||
Container::Vector<Memory::unique_ptr<Thread>>::iterator active = nullptr;
|
Container::Vector<Memory::unique_ptr<Thread>>::iterator active = nullptr;
|
||||||
|
|
||||||
// Scheduler wird evt. von einer Unterbrechung vom Zeitgeber gerufen,
|
// Scheduler wird evt. von einer Unterbrechung vom Zeitgeber gerufen,
|
||||||
// bevor er initialisiert wurde
|
// bevor er initialisiert wurde
|
||||||
uint32_t idle_tid = 0U;
|
uint32_t idle_tid = 0;
|
||||||
|
|
||||||
// Roughly the old dispatcher functionality
|
// Roughly the old dispatcher functionality
|
||||||
void start(Container::Vector<Memory::unique_ptr<Thread>>::iterator next); // Start next without prev
|
void
|
||||||
void switch_to(Thread *prev_raw, Container::Vector<Memory::unique_ptr<Thread>>::iterator next); // Switch from prev to next
|
start(Container::Vector<Memory::unique_ptr<Thread>>::iterator next); // Start next without prev
|
||||||
|
void switch_to(Thread *prev_raw,
|
||||||
|
Container::Vector<Memory::unique_ptr<Thread>>::iterator next); // Switch from prev to next
|
||||||
|
|
||||||
// Kann nur vom Idle-Thread aufgerufen werden (erster Thread der vom Scheduler gestartet wird)
|
// Kann nur vom Idle-Thread aufgerufen werden (erster Thread der vom Scheduler gestartet wird)
|
||||||
void enable_preemption(uint32_t tid) { idle_tid = tid; }
|
void enable_preemption(uint32_t tid) { idle_tid = tid; }
|
||||||
@ -56,14 +59,14 @@ public:
|
|||||||
block_queue.reserve();
|
block_queue.reserve();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t get_active() const {
|
[[nodiscard]] uint32_t get_active() const {
|
||||||
return (*active)->tid;
|
return (*active)->tid;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scheduler initialisiert?
|
// Scheduler initialisiert?
|
||||||
// Zeitgeber-Unterbrechung kommt evt. bevor der Scheduler fertig
|
// Zeitgeber-Unterbrechung kommt evt. bevor der Scheduler fertig
|
||||||
// intiialisiert wurde!
|
// intiialisiert wurde!
|
||||||
bool preemption_enabled() const { return idle_tid != 0U; }
|
[[nodiscard]] bool preemption_enabled() const { return idle_tid != 0U; }
|
||||||
|
|
||||||
// Scheduler starten
|
// Scheduler starten
|
||||||
void schedule();
|
void schedule();
|
||||||
|
|||||||
@ -6,57 +6,73 @@
|
|||||||
|
|
||||||
namespace Container {
|
namespace Container {
|
||||||
|
|
||||||
template<typename T, const std::size_t N>
|
/**
|
||||||
class Array {
|
* This class implements a stack allocated array with bounds checking
|
||||||
public:
|
* and iterator support.
|
||||||
using iterator = ContinuousIterator<T>;
|
*
|
||||||
|
* @tparam T The type of the objects
|
||||||
|
* @tparam N The number of elements the array can store
|
||||||
|
*/
|
||||||
|
template<typename T, const std::size_t N>
|
||||||
|
class Array {
|
||||||
|
public:
|
||||||
|
using iterator = ContinuousIterator<T>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T buf[N];
|
T buf[N];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Array() = default; // If i write default something like bse::array<int, 10> arr; is not initialized...
|
Array() = default; // If i write default something like Container::Array<int, 10> arr; is not initialized...
|
||||||
|
|
||||||
// Construct like this: bse::array<int, 5> {1, 2, 3, 4, 5};
|
// TODO: This doesn't account for initializer lists of the wrong length, last value should be repeated
|
||||||
Array(std::initializer_list<T> list) {
|
// Only increment iterator when it < list.end() - 1?
|
||||||
typename std::initializer_list<T>::iterator it = list.begin();
|
// Construct like this: bse::array<int, 5> {1, 2, 3, 4, 5};
|
||||||
for (unsigned int i = 0; i < N; ++i) {
|
Array(std::initializer_list<T> list) {
|
||||||
buf[i] = *it;
|
typename std::initializer_list<T>::iterator it = list.begin();
|
||||||
++it;
|
for (unsigned int i = 0; i < N; ++i) {
|
||||||
}
|
buf[i] = *it;
|
||||||
|
++it;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
iterator begin() { return iterator(&buf[0]); }
|
// TODO: Rest of constructors
|
||||||
iterator begin() const { return iterator(&buf[0]); }
|
|
||||||
iterator end() { return iterator(&buf[N]); }
|
|
||||||
iterator end() const { return iterator(&buf[N]); }
|
|
||||||
|
|
||||||
constexpr T& operator[](std::size_t i) { return buf[i]; }
|
iterator begin() { return iterator(&buf[0]); }
|
||||||
constexpr const T& operator[](std::size_t i) const { return buf[i]; }
|
|
||||||
|
|
||||||
T* data() { return &buf[0]; }
|
iterator begin() const { return iterator(&buf[0]); }
|
||||||
const T* data() const { return &buf[0]; }
|
|
||||||
|
|
||||||
void swap(Array<T, N>& other) {
|
iterator end() { return iterator(&buf[N]); }
|
||||||
for (std::size_t i = 0; i < N; ++i) {
|
|
||||||
std::swap(buf[i], other[i]);
|
iterator end() const { return iterator(&buf[N]); }
|
||||||
}
|
|
||||||
|
constexpr T &operator[](std::size_t i) { return buf[i]; }
|
||||||
|
|
||||||
|
constexpr const T &operator[](std::size_t i) const { return buf[i]; }
|
||||||
|
|
||||||
|
T *data() { return &buf[0]; }
|
||||||
|
|
||||||
|
const T *data() const { return &buf[0]; }
|
||||||
|
|
||||||
|
void swap(Array<T, N> &other) {
|
||||||
|
for (std::size_t i = 0; i < N; ++i) {
|
||||||
|
std::swap(buf[i], other[i]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Array& other has to have size n:
|
// Array& other has to have size n:
|
||||||
// arr1.swap_n<5>(arr2) => arr2 has size 5, arr1 has size >= 5
|
// arr1.swap_n<5>(arr2) => arr2 has size 5, arr1 has size >= 5
|
||||||
template<std::size_t n>
|
template<std::size_t n>
|
||||||
void swap_n(Array<T, n>& other) {
|
void swap_n(Array<T, n> &other) {
|
||||||
for (std::size_t i = 0; i < n; ++i) {
|
for (std::size_t i = 0; i < n; ++i) {
|
||||||
std::swap(buf[i], other[i]);
|
std::swap(buf[i], other[i]);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
constexpr std::size_t size() const {
|
[[nodiscard]] constexpr std::size_t size() const {
|
||||||
return N;
|
return N;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace bse
|
} // namespace Container
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -3,58 +3,69 @@
|
|||||||
|
|
||||||
namespace Container {
|
namespace Container {
|
||||||
|
|
||||||
// This iterator works for structures where the elements are adjacent in memory.
|
// This iterator works for structures where the elements are adjacent in memory.
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class ContinuousIterator {
|
class ContinuousIterator {
|
||||||
private:
|
private:
|
||||||
T* ptr = nullptr;
|
T *ptr = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ContinuousIterator() = delete;
|
ContinuousIterator() = delete;
|
||||||
|
|
||||||
// Use const_cast as the iterator has to increment the pointer
|
// Use const_cast as the iterator has to increment the pointer
|
||||||
ContinuousIterator(const T* ptr) : ptr(const_cast<T*>(ptr)) {}
|
// Don't make this explicit: Want to write Container::Vector<int>::iterator = nullptr;
|
||||||
|
ContinuousIterator(const T *ptr) : ptr(const_cast<T *>(ptr)) {}
|
||||||
|
|
||||||
ContinuousIterator& operator++() {
|
// TODO: Rest of constructors
|
||||||
++ptr;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
ContinuousIterator& operator--() {
|
ContinuousIterator &operator++() {
|
||||||
--ptr;
|
++ptr;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
|
||||||
|
|
||||||
ContinuousIterator operator+(unsigned int add) {
|
|
||||||
return ContinuousIterator(ptr + add);
|
|
||||||
}
|
|
||||||
|
|
||||||
ContinuousIterator operator-(unsigned int sub) {
|
|
||||||
return ContinuousIterator(ptr - sub);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convenience
|
|
||||||
T* operator->() { return ptr; }
|
|
||||||
const T* operator->() const { return ptr; }
|
|
||||||
T& operator*() { return *ptr; }
|
|
||||||
const T& operator*() const { return *ptr; }
|
|
||||||
|
|
||||||
bool operator<(const ContinuousIterator& other) const { return ptr < other.ptr; }
|
|
||||||
bool operator<=(const ContinuousIterator& other) const { return ptr <= other.ptr; }
|
|
||||||
bool operator>(const ContinuousIterator& other) const { return ptr > other.ptr; }
|
|
||||||
bool operator>=(const ContinuousIterator& other) const { return ptr >= other.ptr; }
|
|
||||||
bool operator==(const ContinuousIterator& other) const { return ptr == other.ptr; }
|
|
||||||
bool operator!=(const ContinuousIterator& other) const { return ptr != other.ptr; }
|
|
||||||
|
|
||||||
template<typename t>
|
|
||||||
friend unsigned int distance(const ContinuousIterator<t>& first, const ContinuousIterator<t>& last);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
unsigned int distance(const ContinuousIterator<T>& first, const ContinuousIterator<T>& last) {
|
|
||||||
return last.ptr - first.ptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ContinuousIterator &operator--() {
|
||||||
|
--ptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ContinuousIterator operator+(unsigned int add) {
|
||||||
|
return ContinuousIterator(ptr + add);
|
||||||
|
}
|
||||||
|
|
||||||
|
ContinuousIterator operator-(unsigned int sub) {
|
||||||
|
return ContinuousIterator(ptr - sub);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convenience
|
||||||
|
T *operator->() { return ptr; }
|
||||||
|
|
||||||
|
const T *operator->() const { return ptr; }
|
||||||
|
|
||||||
|
T &operator*() { return *ptr; }
|
||||||
|
|
||||||
|
const T &operator*() const { return *ptr; }
|
||||||
|
|
||||||
|
bool operator<(const ContinuousIterator &other) const { return ptr < other.ptr; }
|
||||||
|
|
||||||
|
bool operator<=(const ContinuousIterator &other) const { return ptr <= other.ptr; }
|
||||||
|
|
||||||
|
bool operator>(const ContinuousIterator &other) const { return ptr > other.ptr; }
|
||||||
|
|
||||||
|
bool operator>=(const ContinuousIterator &other) const { return ptr >= other.ptr; }
|
||||||
|
|
||||||
|
bool operator==(const ContinuousIterator &other) const { return ptr == other.ptr; }
|
||||||
|
|
||||||
|
bool operator!=(const ContinuousIterator &other) const { return ptr != other.ptr; }
|
||||||
|
|
||||||
|
template<typename t>
|
||||||
|
friend unsigned int distance(const ContinuousIterator<t> &first, const ContinuousIterator<t> &last);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
unsigned int distance(const ContinuousIterator<T> &first, const ContinuousIterator<T> &last) {
|
||||||
|
return last.ptr - first.ptr;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace bse
|
} // namespace bse
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -11,292 +11,296 @@
|
|||||||
// https://en.cppreference.com/w/cpp/container/vector
|
// https://en.cppreference.com/w/cpp/container/vector
|
||||||
namespace Container {
|
namespace Container {
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class Vector {
|
class Vector {
|
||||||
public:
|
public:
|
||||||
using iterator = ContinuousIterator<T>;
|
using iterator = ContinuousIterator<T>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr const std::size_t default_cap = 10; // Arbitrary but very small because this isn't a real OS :(
|
static constexpr const std::size_t default_cap = 10; // Arbitrary but very small because this isn't a real OS :(
|
||||||
static constexpr const std::size_t min_cap = 5; // Slots to allocate extra when array full
|
static constexpr const std::size_t min_cap = 5; // Slots to allocate extra when array full
|
||||||
|
|
||||||
T* buf = nullptr; // Heap allocated as size needs to change during runtime
|
T *buf = nullptr; // Heap allocated as size needs to change during runtime
|
||||||
// Can't use Array for the same reason so we use a C Style array
|
// Can't use Array for the same reason so we use a C Style array
|
||||||
std::size_t buf_pos = 0;
|
std::size_t buf_pos = 0;
|
||||||
std::size_t buf_cap = 0;
|
std::size_t buf_cap = 0;
|
||||||
|
|
||||||
void init(std::size_t cap = Vector::default_cap) {
|
void init(std::size_t cap = Vector::default_cap) {
|
||||||
if (buf != nullptr) {
|
if (buf != nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
buf = new T[cap];
|
buf = new T[cap];
|
||||||
buf_cap = cap;
|
buf_cap = cap;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] std::size_t get_rem_cap() const {
|
||||||
|
return buf_cap - size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enlarges the buffer if we run out of space
|
||||||
|
void min_expand() {
|
||||||
|
// Init if necessary
|
||||||
|
if (buf == nullptr) {
|
||||||
|
init();
|
||||||
|
return; // Dont have to realloc after init
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::size_t get_rem_cap() const {
|
// Since we only ever add single elements this should never get below zero
|
||||||
return buf_cap - size();
|
if (get_rem_cap() < min_cap) {
|
||||||
|
switch_buf(buf_cap + min_cap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Allocates new buffer
|
||||||
|
// 2. Moves stuff to new buffer
|
||||||
|
// 3. Deletes old buffer
|
||||||
|
// 4. Sets new pos/cap
|
||||||
|
void switch_buf(std::size_t cap) {
|
||||||
|
// Alloc new array
|
||||||
|
T *new_buf = new T[cap];
|
||||||
|
|
||||||
|
// Swap current elements to new array
|
||||||
|
for (std::size_t i = 0; i < size(); ++i) {
|
||||||
|
new_buf[i] = std::move(buf[i]);
|
||||||
|
buf[i].~T(); // TODO: I think delete[] buf calls these, verify that
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enlarges the buffer if we run out of space
|
// Move new array to buf, deleting the old array
|
||||||
void min_expand() {
|
delete[] buf;
|
||||||
// Init if necessary
|
buf = new_buf;
|
||||||
if (buf == nullptr) {
|
buf_cap = cap;
|
||||||
init();
|
}
|
||||||
return; // Dont have to realloc after init
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since we only ever add single elements this should never get below zero
|
// Index is location where space should be made
|
||||||
if (get_rem_cap() < min_cap) {
|
void copy_right(std::size_t i) {
|
||||||
switch_buf(buf_cap + min_cap);
|
if (i >= size()) {
|
||||||
}
|
// We don't need to copy anything as space is already there
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. Allocates new buffer
|
for (std::size_t idx = size(); idx > i; --idx) {
|
||||||
// 2. Moves stuff to new buffer
|
buf[idx].~T(); // Delete previously contained element that will be overridden
|
||||||
// 3. Deletes old buffer
|
buf[idx] = std::move(buf[idx - 1]); // This leaves a "shell" of the old object that has to be deleted
|
||||||
// 4. Sets new pos/cap
|
buf[idx - 1].~T(); // Delete element in moved-out state
|
||||||
void switch_buf(std::size_t cap) {
|
}
|
||||||
// Alloc new array
|
}
|
||||||
T* new_buf = new T[cap];
|
|
||||||
|
|
||||||
// Swap current elements to new array
|
// Index is the location that will be removed
|
||||||
for (std::size_t i = 0; i < size(); ++i) {
|
void copy_left(std::size_t i) {
|
||||||
new_buf[i] = std::move(buf[i]);
|
if (i >= size()) {
|
||||||
buf[i].~T(); // TODO: I think delete[] buf calls these, verify that
|
// We don't need to copy anything as nothing will be overridden
|
||||||
}
|
return;
|
||||||
|
|
||||||
// Move new array to buf, deleting the old array
|
|
||||||
delete[] buf;
|
|
||||||
buf = new_buf;
|
|
||||||
buf_cap = cap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Index is location where space should be made
|
for (std::size_t idx = i; idx < size(); ++idx) {
|
||||||
void copy_right(std::size_t i) {
|
buf[idx].~T(); // Delete the element that will be overwritten
|
||||||
if (i >= size()) {
|
buf[idx] = std::move(buf[idx + 1]);
|
||||||
// We don't need to copy anything as space is already there
|
buf[idx + 1].~T();
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::size_t idx = size(); idx > i; --idx) {
|
|
||||||
buf[idx].~T(); // Delete previously contained element that will be overridden
|
|
||||||
buf[idx] = std::move(buf[idx - 1]); // This leaves a "shell" of the old object that has to be deleted
|
|
||||||
buf[idx - 1].~T(); // Delete element in moved-out state
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Index is the location that will be removed
|
public:
|
||||||
void copy_left(std::size_t i) {
|
explicit Vector(bool lazy = false) {
|
||||||
if (i >= size()) {
|
if (!lazy) { // I added this as a work around, the scheduler can't initialize the queues right
|
||||||
// We don't need to copy anything as nothing will be overridden
|
// away because when the scheduler is started the allocator is not ready.
|
||||||
return;
|
init();
|
||||||
}
|
|
||||||
|
|
||||||
for (std::size_t idx = i; idx < size(); ++idx) {
|
|
||||||
buf[idx].~T(); // Delete the element that will be overwritten
|
|
||||||
buf[idx] = std::move(buf[idx + 1]);
|
|
||||||
buf[idx + 1].~T();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
// TODO: This doesn't account for initializer lists of the wrong length, last value should be repeated
|
||||||
explicit Vector(bool lazy = false) {
|
// Only increment iterator when it < list.end() - 1?
|
||||||
if (!lazy) { // I added this as a work around, the scheduler can't initialize the queues right
|
// Initialize like this: bse::vector<int> vec {1, 2, 3, 4, 5};
|
||||||
// away because when the scheduler is started the allocator is not ready.
|
Vector(std::initializer_list<T> list) : buf_cap(list.size()), buf(new T[buf_cap]) {
|
||||||
init();
|
typename std::initializer_list<T>::iterator it = list.begin();
|
||||||
}
|
for (unsigned int i = 0; i < buf_pos; ++i) {
|
||||||
};
|
buf[i] = *it;
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize like this: bse::vector<int> vec {1, 2, 3, 4, 5};
|
Vector(const Vector ©) : buf_pos(copy.buf_pos), buf_cap(copy.buf_cap), buf(new T[buf_cap]) {
|
||||||
Vector(std::initializer_list<T> list) : buf_cap(list.size()), buf(new T[buf_cap]) {
|
for (unsigned int i = 0; i < buf_pos; ++i) {
|
||||||
typename std::initializer_list<T>::iterator it = list.begin();
|
buf[i] = copy[i]; // Does a copy since copy is marked const reference
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector &operator=(const Vector ©) {
|
||||||
|
if (this != ©) {
|
||||||
|
~Vector();
|
||||||
|
|
||||||
|
buf_cap = copy.buf_cap;
|
||||||
|
buf_pos = copy.buf_pos;
|
||||||
|
buf = new T[buf_cap];
|
||||||
for (unsigned int i = 0; i < buf_pos; ++i) {
|
for (unsigned int i = 0; i < buf_pos; ++i) {
|
||||||
buf[i] = *it;
|
buf[i] = copy[i];
|
||||||
++it;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector(Vector &&move) noexcept: buf(move.buf), buf_pos(move.buf_pos), buf_cap(move.buf_cap) {
|
||||||
|
move.buf_cap = 0;
|
||||||
|
move.buf_pos = 0;
|
||||||
|
move.buf = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
Vector(const Vector& copy) : buf_pos(copy.buf_pos), buf_cap(copy.buf_cap), buf(new T[buf_cap]) {
|
Vector &operator=(Vector &&move) noexcept {
|
||||||
for (unsigned int i = 0; i < buf_pos; ++i) {
|
if (this != &move) {
|
||||||
buf[i] = copy[i]; // Does a copy since copy is marked const reference
|
buf_cap = move.buf_cap;
|
||||||
}
|
buf_pos = move.buf_pos;
|
||||||
}
|
buf = move.buf;
|
||||||
|
|
||||||
Vector& operator=(const Vector& copy) {
|
|
||||||
if (this != ©) {
|
|
||||||
~Vector();
|
|
||||||
|
|
||||||
buf_cap = copy.buf_cap;
|
|
||||||
buf_pos = copy.buf_pos;
|
|
||||||
buf = new T[buf_cap];
|
|
||||||
for (unsigned int i = 0; i < buf_pos; ++i) {
|
|
||||||
buf[i] = copy[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector(Vector&& move) noexcept : buf(move.buf), buf_pos(move.buf_pos), buf_cap(move.buf_cap) {
|
|
||||||
move.buf_cap = 0;
|
move.buf_cap = 0;
|
||||||
move.buf_pos = 0;
|
move.buf_pos = 0;
|
||||||
move.buf = nullptr;
|
move.buf = nullptr;
|
||||||
}
|
}
|
||||||
|
return *this;
|
||||||
Vector& operator=(Vector&& move) noexcept {
|
|
||||||
if (this != &move) {
|
|
||||||
buf_cap = move.buf_cap;
|
|
||||||
buf_pos = move.buf_pos;
|
|
||||||
buf = move.buf;
|
|
||||||
|
|
||||||
move.buf_cap = 0;
|
|
||||||
move.buf_pos = 0;
|
|
||||||
move.buf = nullptr;
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
~Vector() {
|
|
||||||
if (buf == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::size_t i = 0; i < size(); ++i) {
|
|
||||||
buf[i].~T(); // TODO: I think delete[] buf calls these, verify that
|
|
||||||
}
|
|
||||||
delete[] buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterator
|
|
||||||
iterator begin() { return iterator(&buf[0]); }
|
|
||||||
iterator begin() const { return iterator(&buf[0]); }
|
|
||||||
iterator end() { return iterator(&buf[size()]); }
|
|
||||||
iterator end() const { return iterator(&buf[size()]); }
|
|
||||||
|
|
||||||
// Add elements
|
|
||||||
// https://en.cppreference.com/w/cpp/container/vector/push_back
|
|
||||||
void push_back(const T& copy) {
|
|
||||||
buf[size()] = copy;
|
|
||||||
++buf_pos;
|
|
||||||
min_expand();
|
|
||||||
}
|
|
||||||
|
|
||||||
void push_back(T&& move) {
|
|
||||||
buf[size()] = std::move(move);
|
|
||||||
++buf_pos;
|
|
||||||
min_expand();
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://en.cppreference.com/w/cpp/container/vector/insert
|
|
||||||
// The element will be inserted before the pos iterator, pos can be the end() iterator
|
|
||||||
iterator insert(iterator pos, const T& copy) {
|
|
||||||
std::size_t idx = distance(begin(), pos); // begin() does init if necessary
|
|
||||||
copy_right(idx); // nothing will be done if pos == end()
|
|
||||||
buf[idx] = copy;
|
|
||||||
++buf_pos;
|
|
||||||
min_expand();
|
|
||||||
return iterator(&buf[idx]);
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator insert(iterator pos, T&& move) {
|
|
||||||
std::size_t idx = distance(begin(), pos); // begin() does init if necessary
|
|
||||||
copy_right(idx);
|
|
||||||
buf[idx] = std::move(move);
|
|
||||||
++buf_pos;
|
|
||||||
min_expand();
|
|
||||||
return iterator(&buf[idx]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove elements
|
|
||||||
// https://en.cppreference.com/w/cpp/container/vector/erase
|
|
||||||
// Returns the iterator after the removed element, pos can't be end() iterator
|
|
||||||
iterator erase(iterator pos) {
|
|
||||||
std::size_t idx = distance(begin(), pos);
|
|
||||||
copy_left(idx);
|
|
||||||
--buf_pos;
|
|
||||||
// shrink();
|
|
||||||
return iterator(&buf[idx]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Access
|
|
||||||
T& front() {
|
|
||||||
return buf[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
const T& front() const {
|
|
||||||
return buf[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
T& back() {
|
|
||||||
return buf[size() - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
const T& back() const {
|
|
||||||
return buf[size() - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
T& operator[](std::size_t pos) {
|
|
||||||
return buf[pos];
|
|
||||||
}
|
|
||||||
|
|
||||||
const T& operator[](std::size_t pos) const {
|
|
||||||
return buf[pos];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Misc
|
|
||||||
[[nodiscard]] bool empty() const {
|
|
||||||
return !size();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] std::size_t size() const {
|
|
||||||
return buf_pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear() {
|
|
||||||
while (buf_pos > 0) {
|
|
||||||
--buf_pos;
|
|
||||||
buf[buf_pos].~T();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void reserve(std::size_t cap = Vector::default_cap) {
|
|
||||||
// The first reserve could allocate double if cap != default_cap
|
|
||||||
if (buf == nullptr) {
|
|
||||||
// Directly init with correct size
|
|
||||||
init(cap);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cap == buf_cap) {
|
|
||||||
// Would change nothing
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch_buf(cap);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] bool initialized() const {
|
|
||||||
return buf != nullptr;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Erase all elements that match a predicate
|
|
||||||
// NOTE: pred is no real predicate as one would need closures for this, but we don't have <functional> available
|
|
||||||
// This means the result has to be passed separately and the function differs from the c++20 std::erase_if
|
|
||||||
template<typename T, typename arg>
|
|
||||||
std::size_t erase_if(Vector<T>& vec, arg (*pred)(const T&), arg result) {
|
|
||||||
std::size_t erased_els = 0;
|
|
||||||
for (typename Vector<T>::Iterator it = vec.begin(); it != vec.end(); /*Do nothing*/) {
|
|
||||||
if (pred(*it) == result) {
|
|
||||||
it = vec.erase(it); // erase returns the iterator to the next element
|
|
||||||
++erased_els;
|
|
||||||
} else {
|
|
||||||
++it; // move forward when nothing was deleted
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return erased_els;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace bse
|
~Vector() {
|
||||||
|
if (buf == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < size(); ++i) {
|
||||||
|
buf[i].~T(); // TODO: I think delete[] buf calls these, verify that
|
||||||
|
}
|
||||||
|
delete[] buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterator
|
||||||
|
iterator begin() { return iterator(&buf[0]); }
|
||||||
|
|
||||||
|
iterator begin() const { return iterator(&buf[0]); }
|
||||||
|
|
||||||
|
iterator end() { return iterator(&buf[size()]); }
|
||||||
|
|
||||||
|
iterator end() const { return iterator(&buf[size()]); }
|
||||||
|
|
||||||
|
// Add elements
|
||||||
|
// https://en.cppreference.com/w/cpp/container/vector/push_back
|
||||||
|
void push_back(const T ©) {
|
||||||
|
buf[size()] = copy;
|
||||||
|
++buf_pos;
|
||||||
|
min_expand();
|
||||||
|
}
|
||||||
|
|
||||||
|
void push_back(T &&move) {
|
||||||
|
buf[size()] = std::move(move);
|
||||||
|
++buf_pos;
|
||||||
|
min_expand();
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://en.cppreference.com/w/cpp/container/vector/insert
|
||||||
|
// The element will be inserted before the pos iterator, pos can be the end() iterator
|
||||||
|
iterator insert(iterator pos, const T ©) {
|
||||||
|
std::size_t idx = distance(begin(), pos); // begin() does init if necessary
|
||||||
|
copy_right(idx); // nothing will be done if pos == end()
|
||||||
|
buf[idx] = copy;
|
||||||
|
++buf_pos;
|
||||||
|
min_expand();
|
||||||
|
return iterator(&buf[idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator insert(iterator pos, T &&move) {
|
||||||
|
std::size_t idx = distance(begin(), pos); // begin() does init if necessary
|
||||||
|
copy_right(idx);
|
||||||
|
buf[idx] = std::move(move);
|
||||||
|
++buf_pos;
|
||||||
|
min_expand();
|
||||||
|
return iterator(&buf[idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove elements
|
||||||
|
// https://en.cppreference.com/w/cpp/container/vector/erase
|
||||||
|
// Returns the iterator after the removed element, pos can't be end() iterator
|
||||||
|
iterator erase(iterator pos) {
|
||||||
|
std::size_t idx = distance(begin(), pos);
|
||||||
|
copy_left(idx);
|
||||||
|
--buf_pos;
|
||||||
|
// shrink();
|
||||||
|
return iterator(&buf[idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Access
|
||||||
|
T &front() {
|
||||||
|
return buf[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
const T &front() const {
|
||||||
|
return buf[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
T &back() {
|
||||||
|
return buf[size() - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
const T &back() const {
|
||||||
|
return buf[size() - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
T &operator[](std::size_t pos) {
|
||||||
|
return buf[pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
const T &operator[](std::size_t pos) const {
|
||||||
|
return buf[pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Misc
|
||||||
|
[[nodiscard]] bool empty() const {
|
||||||
|
return !size();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] std::size_t size() const {
|
||||||
|
return buf_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
while (buf_pos > 0) {
|
||||||
|
--buf_pos;
|
||||||
|
buf[buf_pos].~T();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void reserve(std::size_t cap = Vector::default_cap) {
|
||||||
|
// The first reserve could allocate double if cap != default_cap
|
||||||
|
if (buf == nullptr) {
|
||||||
|
// Directly init with correct size
|
||||||
|
init(cap);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cap == buf_cap) {
|
||||||
|
// Would change nothing
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch_buf(cap);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool initialized() const {
|
||||||
|
return buf != nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Erase all elements that match a predicate
|
||||||
|
// NOTE: pred is no real predicate as one would need closures for this, but we don't have <functional> available
|
||||||
|
// This means the result has to be passed separately and the function differs from the c++20 std::erase_if
|
||||||
|
template<typename T, typename arg>
|
||||||
|
std::size_t erase_if(Vector<T> &vec, arg (*pred)(const T &), arg result) {
|
||||||
|
std::size_t erased_els = 0;
|
||||||
|
for (typename Vector<T>::Iterator it = vec.begin(); it != vec.end(); /*Do nothing*/) {
|
||||||
|
if (pred(*it) == result) {
|
||||||
|
it = vec.erase(it); // erase returns the iterator to the next element
|
||||||
|
++erased_els;
|
||||||
|
} else {
|
||||||
|
++it; // move forward when nothing was deleted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return erased_els;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Container
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -1,132 +0,0 @@
|
|||||||
#ifndef UniquePointer_Include_H_
|
|
||||||
#define UniquePointer_Include_H_
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
// https://en.cppreference.com/w/cpp/memory/unique_ptr
|
|
||||||
|
|
||||||
// NOTE: Because of the way the scheduling works our functions are not executed completely.
|
|
||||||
// This means that object destructors are not called if the objects live in a scope
|
|
||||||
// that is left because of thread switching (e.g. a threads run function)...
|
|
||||||
|
|
||||||
namespace Memory {
|
|
||||||
|
|
||||||
// T is the type make_unique is called with, meaning int or int[] for example
|
|
||||||
// T_ is the bare type without extents (int in both cases), so we have a
|
|
||||||
// int* pointer type for both unique_ptr<int> and unique_ptr<int[]>
|
|
||||||
template<typename T>
|
|
||||||
class unique_ptr {
|
|
||||||
private:
|
|
||||||
using T_ = std::remove_extent_t<T>;
|
|
||||||
|
|
||||||
T_* ptr = nullptr;
|
|
||||||
|
|
||||||
// Only use make_unique or reset for construction
|
|
||||||
unique_ptr(T_* ptr) : ptr(ptr) {}
|
|
||||||
|
|
||||||
// I didn't want to introduce custom deleters for my small needs
|
|
||||||
void del() {
|
|
||||||
if constexpr (std::is_array_v<T>) {
|
|
||||||
delete[] ptr;
|
|
||||||
} else {
|
|
||||||
delete ptr;
|
|
||||||
}
|
|
||||||
ptr = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
// Forbid copying
|
|
||||||
unique_ptr(const unique_ptr& copy) = delete;
|
|
||||||
unique_ptr& operator=(const unique_ptr& copy) = delete;
|
|
||||||
|
|
||||||
// Construction
|
|
||||||
unique_ptr() = default; // Allow declaration without explicit definition
|
|
||||||
|
|
||||||
template<typename t, typename... Args>
|
|
||||||
friend typename std::enable_if_t<!std::is_array_v<t>, unique_ptr<t>>
|
|
||||||
make_unique(Args&&... args);
|
|
||||||
|
|
||||||
template<typename t>
|
|
||||||
friend typename std::enable_if_t<std::is_array_v<t>, unique_ptr<t>>
|
|
||||||
make_unique(std::size_t size);
|
|
||||||
|
|
||||||
// Deletion
|
|
||||||
~unique_ptr() {
|
|
||||||
del();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Moving
|
|
||||||
unique_ptr(unique_ptr&& move) noexcept { reset(move.release()); };
|
|
||||||
|
|
||||||
// Implicit upcasting is needed: for sth like
|
|
||||||
// unique_ptr<Thread> ptr = make_unique<IdleThread>();
|
|
||||||
// IdleThread is derived from Thread so the assert passes
|
|
||||||
template<typename t>
|
|
||||||
unique_ptr(unique_ptr<t>&& move) noexcept {
|
|
||||||
static_assert(std::is_base_of_v<T, t>, "Has to be derived type");
|
|
||||||
reset(move.release());
|
|
||||||
}
|
|
||||||
|
|
||||||
unique_ptr& operator=(unique_ptr&& move) noexcept {
|
|
||||||
reset(move.release());
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resetting: Replaces managed object, deleting the old one
|
|
||||||
void reset() { del(); }
|
|
||||||
void reset(T_* pt) {
|
|
||||||
del();
|
|
||||||
ptr = pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Release: Releases ownership without deletion
|
|
||||||
T_* release() {
|
|
||||||
// T* old = ptr;
|
|
||||||
// ptr = nullptr;
|
|
||||||
// return old;
|
|
||||||
return std::exchange(ptr, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get: Access the raw pointer without taking ownership
|
|
||||||
T_* get() const {
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pointer operators
|
|
||||||
T_* operator->() { return ptr; }
|
|
||||||
const T_* operator->() const { return ptr; }
|
|
||||||
T_& operator*() { return *ptr; }
|
|
||||||
const T_& operator*() const { return *ptr; }
|
|
||||||
|
|
||||||
explicit operator void*() const { return ptr; }
|
|
||||||
explicit operator bool() const { return (ptr != nullptr); }
|
|
||||||
|
|
||||||
bool operator==(const unique_ptr& other) const { return ptr == other.ptr; }
|
|
||||||
|
|
||||||
// These are only for array unique_ptr but I didn't enforce that
|
|
||||||
T_& operator[](std::size_t i) { return ptr[i]; }
|
|
||||||
const T_& operator[](std::size_t i) const { return ptr[i]; }
|
|
||||||
};
|
|
||||||
|
|
||||||
// make_unique implementation =======================================
|
|
||||||
|
|
||||||
// Allow initialization of unique_ptr<int> with optional constructor arguments
|
|
||||||
// and unique_ptr<int[]> without constructor arguments
|
|
||||||
template<typename T, typename... Args>
|
|
||||||
|
|
||||||
// We make the return type dependent on whether T is an array type or not
|
|
||||||
typename std::enable_if_t<!std::is_array_v<T>, unique_ptr<T>>
|
|
||||||
make_unique(Args&&... args) {
|
|
||||||
return unique_ptr<T>(new T(std::forward<Args>(args)...));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename std::enable_if_t<std::is_array_v<T>, unique_ptr<T>>
|
|
||||||
make_unique(std::size_t size) {
|
|
||||||
using T_ = typename std::remove_extent_t<T>;
|
|
||||||
return unique_ptr<T>(new T_[size]);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace bse
|
|
||||||
|
|
||||||
#endif
|
|
||||||
140
src/lib/memory/UniquePointer.h
Normal file
140
src/lib/memory/UniquePointer.h
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
#ifndef UniquePointer_Include_H_
|
||||||
|
#define UniquePointer_Include_H_
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
// https://en.cppreference.com/w/cpp/memory/unique_ptr
|
||||||
|
|
||||||
|
// NOTE: Because of the way the scheduling works our functions are not executed completely.
|
||||||
|
// This means that object destructors are not called if the objects live in a scope
|
||||||
|
// that is left because of thread switching (e.g. a threads run function)...
|
||||||
|
|
||||||
|
namespace Memory {
|
||||||
|
|
||||||
|
// T is the type make_unique is called with, meaning int or int[] for example
|
||||||
|
// T_ is the bare type without extents (int in both cases), so we have a
|
||||||
|
// int* pointer type for both unique_ptr<int> and unique_ptr<int[]>
|
||||||
|
template<typename T>
|
||||||
|
class unique_ptr {
|
||||||
|
private:
|
||||||
|
using T_ = std::remove_extent_t<T>;
|
||||||
|
|
||||||
|
T_ *ptr = nullptr;
|
||||||
|
|
||||||
|
// TODO: Was there a reason I didn't mark this explicit?
|
||||||
|
// Only use make_unique or reset for construction
|
||||||
|
unique_ptr(T_ *ptr) : ptr(ptr) {}
|
||||||
|
|
||||||
|
// I didn't want to introduce custom deleters for my small needs
|
||||||
|
void del() {
|
||||||
|
if constexpr (std::is_array_v<T>) {
|
||||||
|
delete[] ptr;
|
||||||
|
} else {
|
||||||
|
delete ptr;
|
||||||
|
}
|
||||||
|
ptr = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Forbid copying
|
||||||
|
unique_ptr(const unique_ptr ©) = delete;
|
||||||
|
|
||||||
|
unique_ptr &operator=(const unique_ptr ©) = delete;
|
||||||
|
|
||||||
|
// Construction
|
||||||
|
unique_ptr() = default; // Allow declaration without explicit definition
|
||||||
|
|
||||||
|
template<typename t, typename... Args>
|
||||||
|
friend typename std::enable_if_t<!std::is_array_v<t>, unique_ptr<t>>
|
||||||
|
make_unique(Args &&... args);
|
||||||
|
|
||||||
|
template<typename t>
|
||||||
|
friend typename std::enable_if_t<std::is_array_v<t>, unique_ptr<t>>
|
||||||
|
make_unique(std::size_t size);
|
||||||
|
|
||||||
|
// Deletion
|
||||||
|
~unique_ptr() {
|
||||||
|
del();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Moving
|
||||||
|
unique_ptr(unique_ptr &&move) noexcept { reset(move.release()); };
|
||||||
|
|
||||||
|
// Implicit upcasting is needed: for sth like
|
||||||
|
// unique_ptr<Thread> ptr = make_unique<IdleThread>();
|
||||||
|
// IdleThread is derived from Thread so the assert passes
|
||||||
|
template<typename t>
|
||||||
|
unique_ptr(unique_ptr<t> &&move) noexcept {
|
||||||
|
static_assert(std::is_base_of_v<T, t>, "Has to be derived type");
|
||||||
|
reset(move.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr &operator=(unique_ptr &&move) noexcept {
|
||||||
|
reset(move.release());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resetting: Replaces managed object, deleting the old one
|
||||||
|
void reset() { del(); }
|
||||||
|
|
||||||
|
void reset(T_ *pt) {
|
||||||
|
del();
|
||||||
|
ptr = pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release: Releases ownership without deletion
|
||||||
|
T_ *release() {
|
||||||
|
// T* old = ptr;
|
||||||
|
// ptr = nullptr;
|
||||||
|
// return old;
|
||||||
|
return std::exchange(ptr, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get: Access the raw pointer without taking ownership
|
||||||
|
T_ *get() const {
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pointer operators
|
||||||
|
T_ *operator->() { return ptr; }
|
||||||
|
|
||||||
|
const T_ *operator->() const { return ptr; }
|
||||||
|
|
||||||
|
T_ &operator*() { return *ptr; }
|
||||||
|
|
||||||
|
const T_ &operator*() const { return *ptr; }
|
||||||
|
|
||||||
|
explicit operator void *() const { return ptr; }
|
||||||
|
|
||||||
|
explicit operator bool() const { return (ptr != nullptr); }
|
||||||
|
|
||||||
|
bool operator==(const unique_ptr &other) const { return ptr == other.ptr; }
|
||||||
|
|
||||||
|
// These are only for array unique_ptr but I didn't enforce that
|
||||||
|
T_ &operator[](std::size_t i) { return ptr[i]; }
|
||||||
|
|
||||||
|
const T_ &operator[](std::size_t i) const { return ptr[i]; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// make_unique implementation =======================================
|
||||||
|
|
||||||
|
// Allow initialization of unique_ptr<int> with optional constructor arguments
|
||||||
|
// and unique_ptr<int[]> without constructor arguments
|
||||||
|
template<typename T, typename... Args>
|
||||||
|
|
||||||
|
// We make the return type dependent on whether T is an array type or not
|
||||||
|
typename std::enable_if_t<!std::is_array_v<T>, unique_ptr<T>>
|
||||||
|
make_unique(Args &&... args) {
|
||||||
|
return unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
typename std::enable_if_t<std::is_array_v<T>, unique_ptr<T>>
|
||||||
|
make_unique(std::size_t size) {
|
||||||
|
using T_ = typename std::remove_extent_t<T>;
|
||||||
|
return unique_ptr<T>(new T_[size]);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace bse
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -51,8 +51,6 @@ private:
|
|||||||
CGA::color color_bg;
|
CGA::color color_bg;
|
||||||
bool blink;
|
bool blink;
|
||||||
|
|
||||||
friend class Logger; // Give access to the color
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CGA_Stream(CGA_Stream ©) = delete; // Verhindere Kopieren
|
CGA_Stream(CGA_Stream ©) = delete; // Verhindere Kopieren
|
||||||
|
|
||||||
@ -60,9 +58,9 @@ public:
|
|||||||
pos = 0;
|
pos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// CAn't make singleton because atexit
|
// Can't make singleton because atexit
|
||||||
|
|
||||||
// ~CGA_Stream() override = default;
|
// ~CGA_Stream() override = default;
|
||||||
|
|
||||||
void lock() { sem.p(); }
|
void lock() { sem.p(); }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user