From c5d25736a323ec04dc00f4c49e83c8430f4bf6ff Mon Sep 17 00:00:00 2001 From: ChUrl Date: Sat, 16 Jul 2022 00:58:25 +0200 Subject: [PATCH] add arraylist + demo --- c_os/user/demo/ArrayListDemo.cc | 87 +++++++++++++++ c_os/user/demo/ArrayListDemo.h | 23 ++++ c_os/user/lib/ArrayList.cc | 22 ++++ c_os/user/lib/ArrayList.h | 190 ++++++++++++++++++++++++++++++++ 4 files changed, 322 insertions(+) create mode 100644 c_os/user/demo/ArrayListDemo.cc create mode 100644 c_os/user/demo/ArrayListDemo.h create mode 100644 c_os/user/lib/ArrayList.cc create mode 100644 c_os/user/lib/ArrayList.h diff --git a/c_os/user/demo/ArrayListDemo.cc b/c_os/user/demo/ArrayListDemo.cc new file mode 100644 index 0000000..cc9042e --- /dev/null +++ b/c_os/user/demo/ArrayListDemo.cc @@ -0,0 +1,87 @@ +#include "user/demo/ArrayListDemo.h" + +void ArrayListDemo::run() { + kout << "Initial list size: " << dec << this->list.size() << endl; + + kout << "Adding elements in order" << endl; + for (unsigned int i = 0; i < 5; ++i) { + this->list.insert(i); + } + this->list.print(); + + kout << "Removing all elements from the front" << endl; + for (unsigned int i = 0; i < 5; ++i) { + this->list.remove_first(); + } + this->list.print(); + + // ============================================================ + + kout << "Adding elements in order with realloc" << endl; + for (unsigned int i = 0; i < 10; ++i) { + kout << "Add " << dec << i << endl; + this->list.insert(i); + } + this->list.print(); + + kout << "Removing all elements from the back" << endl; + for (unsigned int i = 0; i < 10; ++i) { + this->list.remove_last(); + } + this->list.print(); + + // ============================================================ + + for (unsigned int i = 0; i < 5; ++i) { + this->list.insert(i); + } + this->list.print(); + + kout << "Adding inside the list (at idx 0, 2, 5)" << endl; + this->list.insert_at(10, 0); + this->list.insert_at(10, 2); + this->list.insert_at(10, 5); + this->list.print(); + + kout << "Removing inside the list (at idx 0, 2, 5)" << endl; + this->list.remove_at(0); + this->list.remove_at(2); + this->list.remove_at(5); + this->list.print(); + + for (unsigned int i = 0; i < 5; ++i) { + this->list.remove_first(); + } + this->list.print(); + + // ============================================================ + + kout << "Mirror scheduling behavior" << endl; + + // These are the threads + int active = 0; // Idle thread + this->list.insert(1); + this->list.insert(2); + this->list.insert(3); + this->list.print(); + + kout << "Starting..." << endl; + for (unsigned int n = 0; n < 10000000; ++n) { + this->list.insert(active); + active = list.remove_first(); + + if (this->list.size() != 3) { + kout << "ERROR: Thread went missing" << endl; + break; + } + + if (n < 5) { + this->list.print(); + } + } + kout << "Finished." << endl; + + this->list.print(); + + scheduler.exit(); +} diff --git a/c_os/user/demo/ArrayListDemo.h b/c_os/user/demo/ArrayListDemo.h new file mode 100644 index 0000000..b6fd7af --- /dev/null +++ b/c_os/user/demo/ArrayListDemo.h @@ -0,0 +1,23 @@ +#ifndef __ArrayListDemo_include__ +#define __ArrayListDemo_include__ + +#include "kernel/Globals.h" +#include "kernel/threads/Thread.h" +#include "user/lib/ArrayList.h" + +class ArrayListDemo : public Thread { +private: + ArrayListDemo(const ArrayListDemo& copy) = delete; + + ArrayList list; + +public: + ArrayListDemo() { + this->list.init(); + kout << "Initialized ArrayListDemo" << endl; + } + + void run() override; +}; + +#endif diff --git a/c_os/user/lib/ArrayList.cc b/c_os/user/lib/ArrayList.cc new file mode 100644 index 0000000..51e22aa --- /dev/null +++ b/c_os/user/lib/ArrayList.cc @@ -0,0 +1,22 @@ +#include "user/lib/ArrayList.h" +#include "kernel/Globals.h" +#include "kernel/threads/Thread.h" + +// NOTE: Implement this here as we need to include globals for printing + +template +void ArrayList::print() const { + if (this->buffer_pos == 0) { + kout << "Print List (0 elements)" << endl; + return; + } + + kout << "Print List (" << dec << this->buffer_pos << " elements): "; + for (unsigned int i = 0; i < this->buffer_pos; ++i) { + kout << dec << this->get(i) << " "; + } + kout << endl; +} + +template class ArrayList; +template class ArrayList; diff --git a/c_os/user/lib/ArrayList.h b/c_os/user/lib/ArrayList.h new file mode 100644 index 0000000..0f86d9d --- /dev/null +++ b/c_os/user/lib/ArrayList.h @@ -0,0 +1,190 @@ +#ifndef __ARRAYLIST_INCLUDE_H_ +#define __ARRAYLIST_INCLUDE_H_ + +// NOTE: I decided to implement this because I wanted some sort of dynamic array (for example for the keyeventmanager). +// Also I wanted to template the Queue (for the scheduler) but with this I can just replace the Queue and use the +// ArrayList instead, without additional effort. +// It's also cool to use the allocator a bit more and introduce realloc because I coded that thing + +#include + +// I put the whole implementation in the header because the templating makes it cumbersome to split +template +class ArrayList { +private: + const unsigned int default_size = 10; // Arbitrary but very small because this isn't a real OS :( + const unsigned int expand_size = 5; // Slots to allocate extra when array full + + unsigned int buffer_size = 10; + unsigned int buffer_pos = 0; + + // TODO: Use user/lib/Array + // I manage the size so I can use pointer arithmetic + T* buffer; + + unsigned int get_free_space() const { + return this->buffer_size - this->buffer_pos; + } + + // Enlarges the buffer if we run out of space + unsigned int expand() { + // Since we only ever add single elements this should never get below zero + // TODO: realloc + if (this->get_free_space() < this->expand_size) { + // We need to realloc the buffer + const unsigned int new_size = this->buffer_size + this->expand_size; + T* new_buffer = new T[new_size]; + // TODO: Use move semantics and managed pointers + for (unsigned int idx = 0; idx < this->buffer_pos; ++idx) { + new_buffer[idx] = this->buffer[idx]; + } + delete[] this->buffer; + this->buffer = new_buffer; + this->buffer_size = new_size; + } + + return this->buffer_size; + } + + // unsigned int shrink {} + + // Returns new pos, both do element copying if necessary, -1 if failed + // Index is location where space should be made/removed + unsigned int copy_right(unsigned int i) { + if (i > this->buffer_pos) { + // Error: No elements here + return -1; + } + + this->expand(); + + // Otherwise i == this->pos and we don't need to copy anything + if (i < this->buffer_pos) { + // Enough space to copy elements after pos i + // Copy to the right to make space + // + // [0 1 2 3 _], expand(0) => [_ 0 1 2 3 _] + // ^ | | + // [0 1 2 3 _], expand(1) => [0 _ 1 2 3 _] + // ^ | | + // pos = 4 pos = 5 + for (unsigned int idx = this->buffer_pos; idx > i; --idx) { // idx > i so idx - 1 is never < 0 + this->buffer[idx] = this->buffer[idx - 1]; + } + + // Only change pos if elements were copied + this->buffer_pos = this->buffer_pos + 1; + } + + return this->buffer_pos; + } + + // Don't realloc here, we don't need to shring the buffer every time + // One could introduce a limit of free space but I don't care for now + // Would be bad if the scheduler triggers realloc everytime a thread is removed (if used as readyqueue)... + unsigned int copy_left(unsigned int i) { + if (i >= this->buffer_pos) { + // Error: No elements here + return -1; + } + + // Decrement before loop because we overwrite 1 element (1 copy less than expand) + this->buffer_pos = this->buffer_pos - 1; + + // [0 1 2 3 _], shrink(1) => [0 2 3 _] + // ^ | | + // pos = 3 pos = 2 + for (unsigned int idx = i; idx < this->buffer_pos; ++idx) { // idx < pos so idx + 1 is never outside of size limit + this->buffer[idx] = this->buffer[idx + 1]; + } + + return this->buffer_pos; + } + +public: + void init() { + this->buffer = new T[this->default_size]; + } + + // Returns new pos + unsigned int insert(T e) { + this->expand(); + this->buffer[this->buffer_pos] = e; + this->buffer_pos = this->buffer_pos + 1; + + return this->buffer_pos; + } + + unsigned int insert_at(T e, unsigned int i) { + if (i > this->buffer_pos) { + // Error: Space between elements + return -1; + } + + if (i == this->buffer_pos) { + // Insert at end + this->insert(e); + return this->buffer_pos; + } + + this->copy_right(i); // Changes pos + this->buffer[i] = e; + + return this->buffer_pos; + } + + // Returns removed element + T remove_at(unsigned int i) { + if (i >= this->buffer_pos) { + // ERROR: No element here + return NULL; + } + + T e = this->buffer[i]; + this->copy_left(i); + return e; + } + + T remove_first() { + return this->remove_at(0); + } + + T remove_last() { + // If index -1 unsigned int will overflow and remove_at will catch that + return this->remove_at(this->buffer_pos - 1); + } + + void remove(T e) { + for (unsigned int i = 0; i < this->buffer_pos; ++i) { + if (this->buffer[i] == e) { + this->copy_left(i); + return; + } + } + } + + T get(unsigned int i) const { + if (i >= this->buffer_pos) { + // ERROR: No element there + return NULL; + } + + return this->buffer[i]; + } + + T first() const { + return this->get(0); + } + + bool empty() const { + return this->buffer_pos == 0; + } + + unsigned int size() const { + return this->buffer_pos; + } + + void print() const; +}; + +#endif