177 lines
2.6 KiB
C++
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)
|
|
{}
|
|
};
|
|
}
|