#ifndef __list__
#define __list__
#include "Forwards.hpp"
#include <utility>
#include "Allocator.hpp"
#include "Reflection.hpp"
#include "Debug/Assertion.hpp"
#if VDEBUG
#include <iosfwd>
#endif
namespace Lib {
template <class C>
class List
{
public:
DECL_ELEMENT_TYPE(C);
explicit List (C head)
:
_head(head),
_tail(0)
{
}
List (C head, List* tail)
:
_head(head),
_tail(tail)
{
}
static List* empty ()
{ return nullptr; }
static bool isEmpty (const List* l)
{
return l == 0;
}
static bool isNonEmpty (const List* l)
{
return l != 0;
}
List* tail() const
{
return _tail;
}
List*& tailReference ()
{
return _tail;
}
List** tailPtr ()
{
return &_tail;
}
const C head () const
{
return _head;
}
C head ()
{
return _head;
}
C& headRef ()
{
return _head;
}
C* headPtr ()
{
return &(this->_head);
}
C second () const
{
return tail()->head();
}
void setHead (C hd)
{
_head = hd;
}
List* setTail(List* tl)
{
List* res = _tail;
_tail = tl;
return res;
}
static void destroy (List *l)
{
if (isEmpty(l)) return;
List* current = l;
for (;;) {
List* next = current->tail();
delete current;
if (isEmpty(next)) return;
current = next;
}
}
static void destroyWithDeletion(List *l)
{
if (isEmpty(l)) return;
List* current = l;
for (;;) {
List* next = current->tail();
delete current->head();
delete current;
if (isEmpty(next)) return;
current = next;
}
}
static List* copy (const List* l)
{
if (isEmpty(l)) return empty();
List* result = new List(l->head());
List* previous = result;
List* rest = l->tail();
while (! isEmpty(rest)) {
List* tmp = new List(rest->_head);
previous->_tail = tmp;
previous = tmp;
rest = rest->_tail;
}
previous->_tail = empty();
return result;
}
static List* append (List* fst, List* snd)
{
if (isEmpty(fst)) return snd;
List* result = new List(fst->head());
List* previous = result;
List* rest = fst->tail();
while(isNonEmpty(rest)) {
List* tmp = new List(rest->head());
previous->setTail(tmp);
previous = tmp;
rest = rest->tail();
}
previous->setTail(snd);
return result;
}
static List* cons(C elem, List* l)
{
return new List(elem, l);
}
static List* fromData(const C* data, std::size_t size) {
List* result = nullptr;
for (std::size_t i = size; i-- > 0;)
result = cons(data[i], result);
return result;
}
static List* singleton(C elem)
{
return new List(elem);
}
static void push(C elem,List* &lst)
{
lst = cons(elem, lst);
}
template<class It>
static void pushFromIterator(It it, List* &lst)
{
while(it.hasNext()) {
push(it.next(), lst);
}
}
static C pop(List* &lst)
{
ASS_NEQ(lst,0);
List* tail = lst->tail();
C result = lst->head();
delete lst;
lst = tail;
return result;
}
static List* concat(List* first,List* second)
{
if (first == 0) return second;
if (second == 0) return first;
List* current = first;
for (;;) {
List* next = current->tail();
if (! next) {
current->setTail(second);
return first;
}
current = next;
}
}
static List* reverse(List* l)
{
if (isEmpty(l)) return empty();
List* result = empty();
while (isNonEmpty(l)) {
List* tl = l->tail();
l->setTail(result);
result = l;
l = tl;
}
return result;
}
static unsigned length(const List *l)
{
unsigned len = 0;
while (isNonEmpty(l)) {
len ++;
l = l->tail();
}
return len;
}
static bool member (C elem, const List* l)
{
while (isNonEmpty(l)) {
if (l->head() == elem) return true;
l = l->tail();
}
return false;
}
static List* remove (C elem, List* l)
{
if (isEmpty(l)) return empty();
if (l->head() == elem) {
List* result = l->tail();
delete l;
return result;
}
if (isEmpty(l->tail())) return l;
List* current = l;
List* next = l->tail();
for (;;) {
if (next->head() == elem) { current->setTail(next->tail());
delete next;
return l;
}
current = next;
next = next->tail();
if (isEmpty(next)) return l;
}
}
static C nth(const List *l, unsigned n)
{
while (n != 0) {
ASS_NEQ(l,0);
l = l->tail();
n--;
}
return l->head();
}
static C deleteNth(List*& lst, int n)
{
ASS (n >= 0);
C result;
List* l = lst;
ASS (isNonEmpty(lst));
if (n == 0) {
result = l->head();
lst = l->tail();
delete l;
return result;
}
List* next = l->tail();
while (--n != 0) {
l = next;
next = next->tail();
ASS (isNonEmpty(next));
}
result = next->head();
l->setTail(next->tail());
delete next;
return result;
}
static List* addLast (List* l, C elem)
{
if (! l) return new List (elem);
List* current;
for (current = l; current->_tail; current = current->_tail) {
}
current->setTail(new List(elem));
return l;
}
static List* split (List* l, int n, List*& rest)
{
if (! l) {
ASS_EQ(n,0);
rest = empty();
return empty();
}
if (n == 0) {
rest = empty();
return l;
}
List* nth = l;
while (--n > 0) {
ASS_NEQ(nth,0);
nth = nth->_tail;
}
ASS_NEQ(nth,0);
rest = nth->_tail;
nth->_tail = empty();
return l;
}
#if VDEBUG
std::string toString(){
std::string h = _head->toString();
if(_tail){
return h+","+_tail->toString();
}
else return h;
}
#endif
class Iterator {
public:
USE_ALLOCATOR(List::Iterator);
DECL_ELEMENT_TYPE(C);
explicit Iterator(const List* l) : _lst (l) {}
C next()
{
ASS_NEQ(_lst,0);
C result = _lst->head();
_lst = _lst->tail();
return result;
}
C peekAtNext()
{
return _lst->head();
}
bool hasNext() const
{
return isNonEmpty(_lst);
}
void reset(const List* l) { _lst = l; }
private:
const List* _lst;
};
Iterator iter() const { return Iterator(this); }
class RefIterator {
public:
USE_ALLOCATOR(List::RefIterator);
DECL_ELEMENT_TYPE(C&);
explicit RefIterator(List* l) : _lst (l) {}
C& next()
{
ASS_NEQ(_lst,0);
C& result = _lst->_head;
_lst = _lst->tail();
return result;
}
bool hasNext() const
{ return isNonEmpty(_lst); }
void reset(List* l) { _lst = l; }
private:
List* _lst;
};
RefIterator iter() { return RefIterator(this); }
class DelIterator {
public:
USE_ALLOCATOR(List::DelIterator);
DECL_ELEMENT_TYPE(C);
DelIterator (List*& l)
:
_lst(l),
_prev(0),
_cur(0)
{}
void reset()
{
_prev = 0;
_cur = 0;
}
C next()
{
if (_cur) { _prev = _cur;
_cur = _cur->tail();
ASS_NEQ(_cur,0);
}
else { _cur = _lst;
}
return _cur->head();
}
bool hasNext()
{
if (_cur) { return _cur->tail() != 0;
}
return isNonEmpty(_lst);
}
void del()
{
ASS_NEQ(_cur,0);
ASS_NEQ(_cur,_prev);
if (_cur == _lst) { _lst = _lst->tail();
delete _cur;
_cur = 0;
return;
}
ASS_NEQ(_prev,0);
_prev->setTail(_cur->tail());
delete _cur;
_cur = _prev;
}
void replace(C elem)
{
ASS_NEQ(_cur,0);
_cur->setHead(elem);
}
void insert (List* lst)
{
ASS_NEQ(_cur, _prev);
if (! lst) return;
List* last = lst;
while (last->tail()) {
last = last->tail();
}
if (_prev)
_prev->setTail(lst);
else _lst = lst;
last->setTail(_cur);
_prev = last;
}
void insert (C elem)
{
ASS_NEQ(_cur, _prev);
List* lst = new List(elem,_cur);
if (_prev)
_prev->setTail(lst);
else _lst = lst;
lst->setTail(_cur);
_prev = lst;
}
private:
List*& _lst;
List* _prev;
List* _cur;
};
RefIterator delIter() { return DelIterator(this); }
template<class Iter>
static List* fromIterator(Iter iter) {
List* result = List::empty();
while (iter.hasNext()) {
List::push(iter.next(), result);
}
return result;
}
class DestructiveIterator {
public:
USE_ALLOCATOR(List::DestructiveIterator);
DECL_ELEMENT_TYPE(C);
explicit
DestructiveIterator(List* l)
: _lst (l)
{}
C next()
{
ASS_NEQ(_lst,0);
return List::pop(_lst);
}
bool hasNext() const
{
return isNonEmpty(_lst);
}
private:
List* _lst;
};
USE_ALLOCATOR(List);
class FIFO {
public:
explicit FIFO() : _first(0), _last(0) {}
bool empty() const {
return !_first;
}
void pushFront(C elem)
{
_first = cons(elem, _first);
if (!_last) {
_last = _first;
}
}
void pushBack(C elem)
{
List* newLast = new List(elem);
if (_last) {
_last->setTail(newLast);
} else {
_first = newLast;
}
_last = newLast;
}
List* list() const
{
return _first;
}
List* clipAtLast() const
{
List* beyondLast = List::empty();
if (_last) {
std::swap(_last->_tail,beyondLast);
}
return beyondLast;
}
protected:
List* _first;
List* _last;
};
protected:
C _head;
List* _tail;
};
template<typename T>
typename List<T>::Iterator getContentIterator(List<T>* lst)
{
return typename List<T>::Iterator(lst);
}
template<typename T>
struct ElementTypeInfo<List<T>* >
{
typedef T Type;
};
template<typename T>
struct IteratorTypeInfo<List<T>* >
{
typedef typename List<T>::Iterator Type;
};
template<typename T>
struct IteratorTypeInfo<const List<T>*>
{
typedef typename List<T>::Iterator Type;
};
#if VDEBUG
template<typename T>
std::ostream& operator<< (std::ostream& out, const List<T>& lstr )
{
const List<T>* lst=&lstr;
out<<'[';
while(lst) {
out<<lst->head();
lst=lst->tail();
if (lst) out << ", ";
}
return out<<']';
}
template<typename T>
std::ostream& operator<< (std::ostream& out, const List<T*>& lstr )
{
const List<T*>* lst=&lstr;
out<<'[';
while(lst) {
out<<(*lst->head());
lst=lst->tail();
if (lst) out << ",\n";
}
return out<<']';
}
#endif
}
#endif