Files
datastructures/lists/linkedlist.hpp

177 lines
2.6 KiB
C++

#include <memory>
#include <stdexcept>
namespace List
{
template<class T>
struct Node
{
T value;
std::unique_ptr<Node<T>> next;
Node(T const & _value)
: value(_value),
next(nullptr)
{}
};
template<class T>
class List
{
protected:
std::unique_ptr<Node<T>> root;
Node<T> * tailPtr;
std::size_t size;
public:
void Append(T const value)
{
++size;
if(tailPtr == nullptr)
{
root = std::make_unique<Node<T>>(value);
tailPtr = root.get();
return;
}
tailPtr->next = std::make_unique<Node<T>>(value);
tailPtr = tailPtr->next.get();
}
void Prepend(T const value)
{
++size;
if(root == nullptr)
{
root = std::make_unique<Node<T>>(value);
tailPtr = root.get();
return;
}
auto newRoot = std::make_unique<Node<T>>(value);
newRoot->next.swap(root);
root.swap(newRoot);
}
void Insert(T const value, std::size_t const index)
{
if(index >= size)
{
throw std::out_of_range("Index is greater or equal to size.");
}
if(index == 0u)
{
Prepend(value);
return;
}
if(index == size - 1u)
{
Append(value);
return;
}
++size;
Node<T> * prevPtr = root.get();
Node<T> * curPtr = root->next.get();
std::size_t currentIndex = 1u;
while(currentIndex < index)
{
prevPtr = curPtr;
curPtr = curPtr->next().get();
}
auto newNode = std::make_unique<Node<T>>(value);
newNode->next.swap(prevPtr->next);
prevPtr->next.swap(newNode);
}
void Delete(std::size_t const index)
{
if(index >= size)
{
throw std::out_of_range("Index is greater or equal to size.");
}
--size;
if(index == 0u)
{
root.swap(root->next);
return;
}
if(index == size - 1u)
{
Node<T> * curPtr = root.get();
std::size_t currentIndex = 0u;
while(currentIndex < index - 2u)
{
curPtr = curPtr->next().get();
}
curPtr->next.release();
return;
}
Node<T> * prevPtr = root.get();
Node<T> * curPtr = root->next.get();
std::size_t currentIndex = 1u;
while(currentIndex < index)
{
prevPtr = curPtr;
curPtr = curPtr->next().get();
}
prevPtr->next.swap(curPtr->next);
}
T & Front()
{
if(size == 0u)
{
throw std::out_of_range("List is empty.");
}
return root->value;
}
T & Back()
{
if(size == 0u)
{
throw std::out_of_range("List is empty.");
}
return tailPtr->value;
}
T & operator[](std::size_t const index)
{
if(index >= size)
{
throw std::out_of_range("Index is greater or equal to size.");
}
Node<T> * currentNode = root.get();
std:size_t currentIndex = 0u;
while(currentIndex < index)
{
currentNode = currentNode->next.get();
}
return currentNode->value;
}
List()
: root(nullptr),
tailPtr(nullptr)
{}
};
}