1

switch list to optional return

This commit is contained in:
2022-07-19 23:09:55 +02:00
parent 78f38f46ef
commit 241699a9bf
3 changed files with 141 additions and 129 deletions

View File

@ -8,6 +8,7 @@
#include "user/lib/List.h" #include "user/lib/List.h"
#include "user/lib/mem/UniquePointer.h" #include "user/lib/mem/UniquePointer.h"
#include <cstddef> #include <cstddef>
#include <type_traits>
#include <utility> #include <utility>
// I put most of the implementation in the header because the templating makes it cumbersome to split // I put most of the implementation in the header because the templating makes it cumbersome to split
@ -164,22 +165,22 @@ public:
} }
// Returns removed element // Returns removed element
Type remove_at(std::size_t i) override { std::optional<Type> remove_at(std::size_t i) override {
if (i >= size()) { if (i >= size()) {
// ERROR: No element here // ERROR: No element here
return NULL; return std::nullopt;
} }
Type e = buf[i]; Type e = std::move(buf[i]);
copy_left(i); copy_left(i);
return e; return std::make_optional(e);
} }
Type remove_first() override { std::optional<Type> remove_first() override {
return remove_at(0); return remove_at(0);
} }
Type remove_last() override { std::optional<Type> remove_last() override {
// If index -1 unsigned int will overflow and remove_at will catch that // If index -1 unsigned int will overflow and remove_at will catch that
return remove_at(size() - 1); return remove_at(size() - 1);
} }
@ -196,20 +197,21 @@ public:
return false; return false;
} }
Type get(std::size_t i) const override { // TODO: All gets should be optional references (c++20)
std::optional<Type> get(std::size_t i) const override {
if (i >= size()) { if (i >= size()) {
// ERROR: No element there // ERROR: No element there
return NULL; return std::nullopt;
} }
return buf[i]; return std::make_optional(buf[i]);
} }
Type first() const override { std::optional<Type> first() const override {
return get(0); return get(0);
} }
Type last() const override { std::optional<Type> last() const override {
return get(size() - 1); // Underflow gets catched by get(unsigned int i) return get(size() - 1); // Underflow gets catched by get(unsigned int i)
} }
@ -222,16 +224,19 @@ public:
} }
void print(OutStream& out) const override { void print(OutStream& out) const override {
// if (empty()) { // Our stream cannot print all types so enable this only for debugging purposes (only int)
// out << "Print List (0 elements)" << endl; if constexpr (std::is_same<Type, int>::value) {
// return; if (empty()) {
// } out << "Print List (0 elements)" << endl;
return;
}
// out << "Print List (" << dec << size() << " elements): "; out << "Print List (" << dec << size() << " elements): ";
// for (std::size_t i = 0; i < size(); ++i) { for (std::size_t i = 0; i < size(); ++i) {
// out << dec << get(i) << " "; out << dec << get(i) << " ";
// } }
// out << endl; out << endl;
}
} }
}; };

View File

@ -12,8 +12,8 @@ private:
public: public:
Wrapper(T value) : value(value) {} Wrapper(T value) : value(value) {}
Wrapper<T>* next = NULL; Wrapper<T>* next = nullptr;
Wrapper<T>* prev = NULL; Wrapper<T>* prev = nullptr;
// Allow conversion to make the ListIterator dereferencing work // Allow conversion to make the ListIterator dereferencing work
operator T() { operator T() {
@ -43,33 +43,34 @@ public:
// Type is T // Type is T
using Type = typename List<T, LinkedListIterator<Wrapper<T>>>::Type; // T is different from the List type (Wrapper<T>) using Type = typename List<T, LinkedListIterator<Wrapper<T>>>::Type; // T is different from the List type (Wrapper<T>)
using Iterator = typename List<T, LinkedListIterator<Wrapper<T>>>::Iterator; using Iterator = typename List<T, LinkedListIterator<Wrapper<T>>>::Iterator;
using Wrapper = typename Iterator::Type;
private: private:
unsigned int num_elements = 0; unsigned int num_elements = 0;
typename Iterator::Type* head = NULL; Wrapper* head = nullptr;
typename Iterator::Type* tail = NULL; Wrapper* tail = nullptr;
typename Iterator::Type* get_wrapper(unsigned int i) { std::optional<Wrapper*> get_wrapper(unsigned int i) {
typename Iterator::Type* current = this->head; Wrapper* current = head;
unsigned int pos = 0; unsigned int pos = 0;
while (current != NULL) { while (current != nullptr) {
if (pos == i) { if (pos == i) {
return current; return std::make_optional(current);
} }
current = current->next; current = current->next;
pos = pos + 1; pos = pos + 1;
} }
return NULL; return std::nullopt;
} }
public: public:
~LinkedList() { ~LinkedList() {
typename Iterator::Type* current = head; Wrapper* current = head;
typename Iterator::Type* next; Wrapper* next;
while (current != NULL) { while (current != nullptr) {
next = current->next; next = current->next;
delete current; delete current;
current = next; current = next;
@ -77,143 +78,145 @@ public:
} }
Iterator begin() override { Iterator begin() override {
return Iterator(this->head); return Iterator(head);
} }
Iterator end() override { Iterator end() override {
return Iterator(this->tail->next); return Iterator(tail->next);
} }
unsigned int insert_at(Type e, unsigned int i) override { unsigned int insert_at(Type e, unsigned int i) override {
if (i > this->size()) { if (i > size()) {
return -1; return -1;
} }
if (i == 0) { if (i == 0) {
return this->insert_first(e); return insert_first(e);
} }
if (i == this->size()) { if (i == size()) {
return this->insert_last(e); return insert_last(e);
} }
typename Iterator::Type* old_e = this->get_wrapper(i); Wrapper* old_e = get_wrapper(i);
typename Iterator::Type* new_e = new typename Iterator::Type(e); Wrapper* new_e = new Wrapper(e);
new_e->prev = old_e->prev; new_e->prev = old_e->prev;
new_e->next = old_e; new_e->next = old_e;
new_e->prev->next = new_e; new_e->prev->next = new_e;
new_e->next->prev = new_e; new_e->next->prev = new_e;
this->num_elements = this->num_elements + 1; num_elements = num_elements + 1;
return this->size(); return size();
} }
unsigned int insert_first(Type e) override { unsigned int insert_first(Type e) override {
typename Iterator::Type* old_head = this->head; Wrapper* old_head = head;
this->head = new typename Iterator::Type(e); head = new Wrapper(e);
this->head->prev = NULL; head->prev = nullptr;
this->head->next = old_head; head->next = old_head;
if (old_head != NULL) { if (old_head != nullptr) {
old_head->prev = this->head; old_head->prev = head;
} }
if (this->tail == NULL) { if (tail == nullptr) {
this->tail = this->head; tail = head;
} }
this->num_elements = this->num_elements + 1; num_elements = num_elements + 1;
return this->size(); return size();
} }
unsigned int insert_last(Type e) override { unsigned int insert_last(Type e) override {
typename Iterator::Type* old_tail = this->tail; Wrapper* old_tail = tail;
this->tail = new typename Iterator::Type(e); tail = new Wrapper(e);
this->tail->next = NULL; tail->next = nullptr;
this->tail->prev = old_tail; tail->prev = old_tail;
if (old_tail != NULL) { if (old_tail != nullptr) {
old_tail->next = this->tail; old_tail->next = tail;
} }
if (this->head == NULL) { if (head == nullptr) {
this->head = this->tail; head = tail;
} }
this->num_elements = this->num_elements + 1; num_elements = num_elements + 1;
return this->size(); return size();
} }
Type remove_at(unsigned int i) override { std::optional<Type> remove_at(unsigned int i) override {
if (this->empty() || i >= this->size()) { if (empty() || i >= size()) {
return NULL; return std::nullopt;
} }
if (i == 0) { if (i == 0) {
return this->remove_first(); return remove_first();
} }
if (i == this->size() - 1) { if (i == size() - 1) {
return this->remove_last(); return remove_last();
} }
typename Iterator::Type* e = this->get_wrapper(i); Wrapper* e = get_wrapper(i);
Type ret = *e; Type ret = *e;
e->next->prev = e->prev; e->next->prev = e->prev;
e->prev->next = e->next; e->prev->next = e->next;
delete e; delete e;
this->num_elements = this->num_elements - 1; num_elements = num_elements - 1;
return ret; return std::make_optional(ret);
} }
Type remove_first() override { std::optional<Type> remove_first() override {
if (this->empty()) { if (empty()) {
return NULL; return std::nullopt;
} }
Type e = *this->head; Type e = *head;
typename Iterator::Type* old_head = this->head; Wrapper* old_head = head;
this->head = this->head->next; head = head->next;
if (this->head != NULL) { if (head != nullptr) {
this->head->prev = NULL; head->prev = nullptr;
} else { } else {
this->tail = NULL; tail = nullptr;
} }
delete old_head; delete old_head;
this->num_elements = this->num_elements - 1; num_elements = num_elements - 1;
return e; return std::make_optional(e);
} }
Type remove_last() override { std::optional<Type> remove_last() override {
if (this->empty()) { if (empty()) {
return NULL; return std::nullopt;
} }
Type e = *this->tail; Type e = *tail;
typename Iterator::Type* old_tail = this->tail; Wrapper* old_tail = tail;
this->tail = this->tail->prev; tail = tail->prev;
if (this->tail != NULL) { if (tail != nullptr) {
this->tail->next = NULL; tail->next = nullptr;
} else { } else {
this->head == NULL; head == nullptr;
} }
delete old_tail; delete old_tail;
this->num_elements = this->num_elements - 1; num_elements = num_elements - 1;
return std::make_optional(e);
} }
bool remove(Type e) override { bool remove(Type e) override {
unsigned int pos = 0; unsigned int pos = 0;
typename Iterator::Type* wrapper = this->head; Wrapper* wrapper = head;
while (wrapper != NULL) { while (wrapper != nullptr) {
if (*wrapper == e) { if (*wrapper == e) {
return remove_at(pos); return remove_at(pos);
} }
@ -223,61 +226,64 @@ public:
} }
} }
Type get(unsigned int i) const override { std::optional<Type> get(unsigned int i) const override {
if (i >= this->size()) { if (i >= size()) {
return NULL; return std::nullopt;
} }
if (i == 0) { if (i == 0) {
return *head; return first();
} }
if (i == this->size() - 1) { if (i == size() - 1) {
return *tail; return last();
} }
typename Iterator::Type* wrapper = this->head; Wrapper* wrapper = head;
for (unsigned int pos = 0; pos < i; ++pos) { for (unsigned int pos = 0; pos < i; ++pos) {
wrapper = wrapper->next; wrapper = wrapper->next;
} }
return *wrapper; return std::make_optional(*wrapper);
} }
Type first() const override { std::optional<Type> first() const override {
if (this->empty()) { if (empty()) {
return NULL; return std::nullopt;
} }
return *this->head; return std::make_optional(*head);
} }
Type last() const override { std::optional<Type> last() const override {
if (this->empty()) { if (empty()) {
return NULL; return std::nullopt;
} }
return *this->tail; return std::make_optional(*tail);
} }
bool empty() const override { bool empty() const override {
return this->size() == 0; return !size();
} }
unsigned int size() const override { unsigned int size() const override {
return this->num_elements; return num_elements;
} }
void print(OutStream& out) const override { void print(OutStream& out) const override {
// if (this->empty()) { // Our stream cannot print all types so enable this only for debugging purposes (only int)
// out << "Print List (0 elements)" << endl; if constexpr (std::is_same<Type, int>::value) {
// return; if (empty()) {
// } out << "Print List (0 elements)" << endl;
return;
}
// out << "Print List (" << dec << this->size() << " elements): "; out << "Print List (" << dec << size() << " elements): ";
// typename Iterator::Type* current = this->head; typename Iterator::Type* current = head;
// while (current != NULL) { while (current != nullptr) {
// out << dec << *current << " "; out << dec << *current << " ";
// current = current->next; current = current->next;
// } }
// out << endl; out << endl;
}
} }
}; };

View File

@ -3,6 +3,7 @@
#include "lib/OutStream.h" #include "lib/OutStream.h"
#include "user/lib/Iterator.h" #include "user/lib/Iterator.h"
#include <optional>
// Define the list interface for ArrayList/LinkedList implementations with support for Iterators/ranged based for loops // Define the list interface for ArrayList/LinkedList implementations with support for Iterators/ranged based for loops
@ -24,15 +25,15 @@ public:
virtual unsigned int insert_last(Type e) = 0; virtual unsigned int insert_last(Type e) = 0;
// Remove // Remove
virtual Type remove_at(unsigned int i) = 0; virtual std::optional<Type> remove_at(unsigned int i) = 0;
virtual Type remove_first() = 0; virtual std::optional<Type> remove_first() = 0;
virtual Type remove_last() = 0; virtual std::optional<Type> remove_last() = 0;
virtual bool remove(Type e) = 0; virtual bool remove(Type e) = 0;
// Get // Get
virtual Type get(unsigned int i) const = 0; virtual std::optional<Type> get(unsigned int i) const = 0;
virtual Type first() const = 0; virtual std::optional<Type> first() const = 0;
virtual Type last() const = 0; virtual std::optional<Type> last() const = 0;
// Misc // Misc
virtual bool empty() const = 0; virtual bool empty() const = 0;