#ifndef INCLUDED_ERASE_H_
#define INCLUDED_ERASE_H_

#include "append.h"

//ERASEIDX
    template <size_t idx, typename TypeList>
    struct EraseIdx;
//=

//ERASEIDXEMPTY
    template <size_t idx>
    struct EraseIdx<idx, TypeList<>>
    {
        using List = TypeList<>;
    };
//=

//ERASEIDXZERO
    template <typename EraseType, typename ...Tail>
    struct EraseIdx<0, TypeList<EraseType, Tail...>>
    {
        using List = TypeList<Tail...>;
    };
//=

//ERASEIDXNEXT
    template <size_t idx, typename Head, typename ...Tail>
    struct EraseIdx<idx, TypeList<Head, Tail...>>
    {
        using List = typename Prefix<
                    Head,
                    typename EraseIdx<idx - 1, TypeList<Tail...>>::List
                >::List;
    };
//=

//ERASEPLAIN
    template <typename EraseType, typename TypeList>
    struct Erase;
//=

//ERASEEMPTY
    template <typename EraseType>
    struct Erase<EraseType, TypeList<>>
    {
        using List = TypeList<>;
    };
//=

//ERASEHEAD
    template <typename EraseType, typename ...Tail>
    struct Erase<EraseType, TypeList<EraseType, Tail...>>
    {
        using List = TypeList<Tail...>;
    };
//=

//ERASENEXT
    template <typename EraseType, typename Head, typename ...Tail>
    struct Erase<EraseType, TypeList<Head, Tail...>>
    {
        using List =  typename
            Prefix<Head,
                typename Erase<EraseType, TypeList<Tail...>>::List
            >::List;
    };
//=

//ERASEALL
    template <typename EraseType, typename TypeList>
    struct EraseAll: public Erase<EraseType, TypeList>
    {};
//=

//ERASEALLTYPES
    template <typename EraseType, typename ...Tail>
    struct EraseAll<EraseType, TypeList<EraseType, Tail...>>
    {
        using List = typename EraseAll<EraseType, TypeList<Tail...>>::List;
    };
//=

//ERASEALLNEXT
    template <typename EraseType, typename Head, typename ...Tail>
    struct EraseAll<EraseType, TypeList<Head, Tail...>>
    {
        using List = typename Prefix<
            Head,
            typename EraseAll<EraseType, TypeList<Tail...>>::List
        >::List;
    };
//=

//ERASEDUP
    template <typename TypeList>
    struct EraseDup;
//=
//ERASEDUPEMPTY
    template <>
    struct EraseDup<TypeList<>>
    {
        using List = TypeList<>;
    };
//=
//ERASEDUPHEAD
    template <typename Head, typename ...Tail>
    struct EraseDup<TypeList<Head, Tail...>>
    {
        using UniqueTail = typename EraseDup<TypeList<Tail...>>::List;
        using NewTail = typename Erase<Head, UniqueTail>::List;

        using List = typename Prefix<Head, NewTail>::List;
    };
//=

#endif
