switch list to optional return
This commit is contained in:
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user