/*
 * Authors:
 *   MenTaLguY <mental@rydia.net>
 *
 * Copyright (C) 2004 MenTaLguY
 *
 * Released under GNU GPL, read the file 'COPYING' for more information
 */

#ifndef SEEN_INKSCAPE_UTIL_LIST_H
#define SEEN_INKSCAPE_UTIL_LIST_H

#include <cstddef>
#include <iterator>
#include "gc-managed.h"
#include "util/reference.h"

namespace Inkscape {

namespace Util {

/// Generic ListCell for Inkscape::Util::List.
template <typename T>
struct ListCell : public GC::Managed<> {
    ListCell() {}
    ListCell(typename Traits::Reference<T>::RValue v, ListCell *n)
    : value(v), next(n) {}

    T value;
    ListCell *next;
};

template <typename T> class List;
template <typename T> class MutableList;

template <typename T>
bool is_empty(List<T> const &list);

template <typename T>
typename List<T>::reference first(List<T> const &list);

template <typename T>
List<T> const &rest(List<T> const &list);

template <typename T>
MutableList<T> &rest(MutableList<T> const &list);

template <typename T>
MutableList<T> const &set_rest(MutableList<T> const &list,
                               MutableList<T> const &rest);

/// Helper template.
template <typename T>
class List<T const> {
public:
    typedef std::forward_iterator_tag iterator_category;
    typedef T const value_type;
    typedef std::ptrdiff_t difference_type;
    typedef typename Traits::Reference<value_type>::LValue reference;
    typedef typename Traits::Reference<value_type>::RValue const_reference;
    typedef typename Traits::Reference<value_type>::Pointer pointer;

    List() : _cell(NULL) {}
    explicit List(const_reference value, List const &next=List())
    : _cell(new ListCell<T>(value, next._cell)) {}

    operator bool() const { return this->_cell; }

    reference operator*() const { return this->_cell->value; }
    pointer operator->() const { return &this->_cell->value; }

    bool operator==(List const &other) const {
        return this->_cell == other._cell;
    }
    bool operator!=(List const &other) const {
        return this->_cell != other._cell;
    }

    List &operator++() {
        this->_cell = this->_cell->next;
        return *this;
    }
    List operator++(int) {
        List old(*this);
        this->_cell = this->_cell->next;
        return old;
    }

    friend reference first<>(List const &);
    friend List const &rest<>(List const &);
    friend bool is_empty<>(List const &);

protected:
    ListCell<T> *_cell;
};

/**
 * Generic linked list.
 * 
 * These lists are designed to store simple values like pointers,
 * references, and scalar values.  While they can be used to directly
 * store more complex objects, destructors for those objects will not
 * be called unless those objects derive from Inkscape::GC::Finalized.
 *
 * In general it's better to use lists to store pointers or references
 * to objects requiring finalization and manage object lifetimes separately.
 *
 * @see Inkscape::GC::Finalized
 *
 * cons() is synonymous with List<T>(first, rest), except that the
 * compiler will usually be able to infer T from the type of \a rest.
 *
 * If you need to create an empty list (which can, for example, be used
 * as an 'end' value with STL algorithms), call the List<> constructor
 * with no arguments, like so:
 *
 * <code>    List<int>()    </code>
 */
template <typename T>
class List : public List<T const> {
public:
    typedef T value_type;
    typedef typename Traits::Reference<value_type>::LValue reference;
    typedef typename Traits::Reference<value_type>::RValue const_reference;
    typedef typename Traits::Reference<value_type>::Pointer pointer;

    List() : List<T const>() {}
    explicit List(const_reference value, List const &next=List())
    : List<T const>(value, next) {}

    reference operator*() const { return this->_cell->value; }
    pointer operator->() const { return &this->_cell->value; }

    List &operator++() {
        this->_cell = this->_cell->next;
        return *this;
    }
    List operator++(int) {
        List old(*this);
        this->_cell = this->_cell->next;
        return old;
    }

    friend reference first<>(List const &);
    friend List const &rest<>(List const &);
    friend bool is_empty<>(List const &);
};

/// Helper template.
template <typename T>
class List<T &> {
public:
    typedef std::forward_iterator_tag iterator_category;
    typedef T &value_type;
    typedef std::ptrdiff_t difference_type;
    typedef typename Traits::Reference<value_type>::LValue reference;
    typedef typename Traits::Reference<value_type>::RValue const_reference;
    typedef typename Traits::Reference<value_type>::Pointer pointer;

    List() : _cell(NULL) {}
    List(const_reference value, List const &next=List())
    : _cell(new ListCell<T &>(value, next._cell)) {}

    operator bool() const { return this->_cell; }

    reference operator*() const { return this->_cell->value; }
    pointer operator->() const { return &this->_cell->value; }

    bool operator==(List const &other) const {
        return this->_cell == other._cell;
    }
    bool operator!=(List const &other) const {
        return this->_cell != other._cell;
    }

    List &operator++() {
        this->_cell = this->_cell->next;
        return *this;
    }
    List operator++(int) {
        List old(*this);
        this->_cell = this->_cell->next;
        return old;
    }

    friend reference first<>(List const &);
    friend List const &rest<>(List const &);
    friend bool is_empty<>(List const &);

protected:
    ListCell<T &> *_cell;
};

/** 
 * Generic MutableList.
 * 
 * Like a linked list, but one whose tail can be exchanged for
 * another later by using set_rest() or assignment through rest()
 * as an lvalue.  It's otherwise identical to the "non-mutable" form.
 *
 * As with List, you can create an empty list like so:
 *
 *  <code>   MutableList<int>()    </code>
 */
template <typename T>
class MutableList : public List<T> {
public:
    MutableList() {}
    explicit MutableList(typename List<T>::const_reference value,
                         MutableList const &next=MutableList())
    : List<T>(value, next) {}

    MutableList &operator++() {
        this->_cell = this->_cell->next;
        return *this;
    }
    MutableList operator++(int) {
        MutableList old(*this);
        this->_cell = this->_cell->next;
        return old;
    }

    friend MutableList &rest<>(MutableList const &);
    friend MutableList const &set_rest<>(MutableList const &,
                                         MutableList const &);
};

/**
 * Creates a (non-empty) linked list.
 * 
 * Creates a new linked list with a copy of the given value (\a first)
 * in its first element; the remainder of the list will be the list
 * provided as \a rest.
 *
 * The remainder of the list -- the "tail" -- is incorporated by
 * reference rather than being copied.
 *
 * The returned value can also be treated as an STL forward iterator.
 *
 * @param first the value for the first element of the list
 * @param rest the rest of the list; may be an empty list
 *
 * @return a new list
 *
 * @see List<>
 * @see is_empty<>
 *
 */
template <typename T>
inline List<T> cons(typename Traits::Reference<T>::RValue first,
                    List<T> const &rest)
{
    return List<T>(first, rest);
}

/**
 * Creates a (non-empty) linked list whose tail can be exchanged
 *         for another.
 *
 * Creates a new linked list, but one whose tail can be exchanged for
 * another later by using set_rest() or assignment through rest()
 * as an lvalue.  It's otherwise identical to the "non-mutable" form.
 *
 * This form of cons() is synonymous with MutableList<T>(first, rest),
 * except that the compiler can usually infer T from the type of \a rest.
 *
 * As with List<>, you can create an empty list like so:
 *
 *  MutableList<int>()
 *
 * @see MutableList<>
 * @see is_empty<>
 *
 * @param first the value for the first element of the list
 * @param rest the rest of the list; may be an empty list
 *
 * @return a new list
 */
template <typename T>
inline MutableList<T> cons(typename Traits::Reference<T>::RValue first,
                           MutableList<T> const &rest)
{
    return MutableList<T>(first, rest);
}

/**
 * Returns true if the given list is empty.
 *
 * Returns true if the given list is empty.  This is equivalent
 * to !list.
 *
 * @param list the list
 *
 * @return true if the list is empty, false otherwise.
 */
template <typename T>
inline bool is_empty(List<T> const &list) { return !list._cell; }

/**
 * Returns the first value in a linked list.
 *
 * Returns a reference to the first value in the list.  This
 * corresponds to the value of the first argument passed to cons().
 *
 * If the list holds mutable values (or references to them), first()
 * can be used as an lvalue.
 *
 * For example:
 * 
 *  first(list) = value;
 *
 * The results of calling this on an empty list are undefined.
 *
 * @see cons<>
 * @see is_empty<>
 *
 * @param list the list; cannot be empty
 *
 * @return a reference to the first value in the list
 */
template <typename T>
inline typename List<T>::reference first(List<T> const &list) {
    return list._cell->value;
}

/**
 * Returns the remainder of a linked list after the first element.
 *
 * Returns the remainder of the list after the first element (its "tail").
 *
 * This will be the same as the second argument passed to cons().
 *
 * The results of calling this on an empty list are undefined.
 *
 * @see cons<>
 * @see is_empty<>
 *
 * @param list the list; cannot be empty
 *
 * @return the remainder of the list
 */
template <typename T>
inline List<T> const &rest(List<T> const &list) {
    return reinterpret_cast<List<T> const &>(list._cell->next);
}

/**
 * Returns a reference to the remainder of a linked list after
 *         the first element.
 *
 * Returns a reference to the remainder of the list after the first
 * element (its "tail").  For MutableList<>, rest() can be used as
 * an lvalue, to set a new tail.
 *
 * For example:
 *
 *  rest(list) = other;
 *
 * Results of calling this on an empty list are undefined.
 *
 * @see cons<>
 * @see is_empty<>
 *
 * @param list the list; cannot be empty
 *
 * @return a reference to the remainder of the list
 */
template <typename T>
inline MutableList<T> &rest(MutableList<T> const &list) {
    return reinterpret_cast<MutableList<T> &>(list._cell->next);
}

/**
 * Sets a new tail for an existing linked list.
 * 
 * Sets the tail of the given MutableList<>, corresponding to the
 * second argument of cons().
 *
 * Results of calling this on an empty list are undefined.
 *
 * @see rest<>
 * @see cons<>
 * @see is_empty<>
 *
 * @param list the list; cannot be empty
 * @param rest the new tail; corresponds to the second argument of cons()
 *
 * @return the new tail
 */
template <typename T>
inline MutableList<T> const &set_rest(MutableList<T> const &list,
                                      MutableList<T> const &rest)
{
    list._cell->next = rest._cell;
    return reinterpret_cast<MutableList<T> &>(list._cell->next);
}

}

}

#endif
/*
  Local Variables:
  mode:c++
  c-file-style:"stroustrup"
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
  indent-tabs-mode:nil
  fill-column:99
  End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
