// { dg-do assemble  }
// prms-id: 1989

#define TRUE true
#define FALSE false
typedef void *Pix;

template<class T>
struct link {
    T item;
    link *next;
    link *prev;

    link(const T& t): item(t), prev(0), next(0)
	{ };
    link(const T& t, link<T> *p, link<T> *n): item(t), prev(p), next(n)
	{ };
};

template<class T>
class List_DL {
public:
    List_DL();
    List_DL(const List_DL&);
    ~List_DL();

    void append(const T& item);
    void prepend(const T& item);
    void insert(const T& item, Pix x, bool before);

    void remove(Pix& x)
	{ T tmp; remove(x, tmp); }
    void remove(Pix& x, T& item);

    void clear();

    unsigned length() const
	{ return count; }

private:

    unsigned count;
    link<T> *head;
    link<T> *tail;

public:
    Pix first() const
	{ return Pix(head); }
    Pix last() const
	{ return Pix(tail); }
    void next(Pix& x) const
	{ if (0 != x) x = ((link<T> *) x)->next; }
    void prev(Pix& x) const
	{ if (0 != x) x = ((link<T> *) x)->prev; }
    T& operator()(Pix x) const
	{ return ((link<T> *) x)->item; }
};

template<class T>
List_DL<T>::List_DL():
count(0),
head(0)
{ }

template<class T>
List_DL<T>::List_DL(const List_DL& other):
count(0),
head(0)
{
    for (Pix x=other.first(); 0 != x; other.next(x))
	append(other(x));
}

template<class T>
List_DL<T>::~List_DL()
{
    clear();
}

template<class T>
void
List_DL<T>::append(const T& item)
{
    count++;
    if (0 == head) {
	head = new link<T>(item);
	tail = head;
    } else {
	tail->next = new link<T>(item, tail, 0);
	tail = tail->next;
    }
}

template<class T>
void
List_DL<T>::prepend(const T& item)
{
    count++;
    if (0 == head) {
	head = new link<T>(item);
	tail = head;
    } else {
	head = new link<T>(item, 0, head);
	if (tail == head)
	    tail = tail->next;
    }
}

template<class T>
void
List_DL<T>::insert(const T& item, Pix x, bool before = TRUE)
{
    link<T> *l = (link<T> *) x;

    if (before) {
	if (0 == l || l == head) {
	    prepend(item);
	} else {
	    link<T> *n = new link<T>(item, l->prev, l);
	    l->prev->next = n;
	    l->prev = n;
	}
    } else {
	if (0 == l || l == tail) {
	    append(item);
	} else {
	    link<T> *n = new link<T>(item, l, l->next);
	    l->next->prev = n;
	    l->prev = n;
	}
    }
}

template<class T>
void
List_DL<T>::remove(Pix& x, T& item)
{
    link<T> *l = (link<T> *) x;

    if (0 == l)
	return;

    item = l->item;
    if (1 == count) {
	delete head;
	head = 0;
	tail = 0;
    } else {
	// more than one item in the list
	if (l == head) {
	    link<T> *old = head;
	    head = head->next;
	    head->prev = 0;
	    delete old;
	} else if (l == tail) {
	    link<T> *old = tail;
	    tail = tail->prev;
	    tail->next = 0;
	    delete old;
	} else {
	    l->next->prev = l->prev;
	    l->prev->next = l->next;
	    delete l;
	}
    }
}

template<class T>
void
List_DL<T>::clear()
{
    link<T> *l, *succ;
    for (l=head; 0 != l; l=succ) {
	succ = l->next;
	delete l;
    }
    head = 0;
    tail = 0;
}

template<class T>
class List_DLS: public List_DL<T> {
public:
    List_DLS(): List_DL<T>()
	{ };
    List_DLS(const List_DLS& other): List_DL<T>(other)
	{ };

    bool contains(const T& item) const
	{ return search(item) != 0 ? TRUE: FALSE; }
    Pix search(const T&) const;
};

template<class T>
Pix
List_DLS<T>::search(const T& item) const
{
    for (Pix x=this->first(); 0 != x; this->next(x)) {
	if (item == this->operator()(x)) // { dg-error "" } const subversion
	    return x;
    }
    return 0;
}

template<class T>
class List_DLSp: public List_DL<T> {
public:
    List_DLSp(): List_DL<T>()
	{ };
    List_DLSp(const List_DLSp& other): List_DL<T>(other)
	{ };

    bool contains(const T& item) const
#ifndef INTERNAL_ERROR
	;
#else
	{ return search(item) != 0 ? TRUE: FALSE; }
#endif
    Pix search(const T&) const;
};

template<class T>
bool
List_DLSp<T>::contains(const T& item) const
{
    for (Pix x=this->first(); 0 != x; this->next(x)) {
        if (*item == *(this->operator()(x)))
	    return TRUE;
    }
    return FALSE;
}

template<class T>
class Set {
public:
    Set();
    Set(const Set& other);

    virtual void add(const T& item);

    void remove(const T& item)
	{ Pix x = search(item); remove(x); }
    void remove(Pix& x)
	{ T tmp; remove(x, tmp); }
    virtual void remove(Pix& x, T& item);

    virtual void clear();

    virtual bool contains(const T&) const;
    virtual Pix search(const T&) const;

    virtual unsigned length() const;

    virtual Pix first() const;
    virtual void next(Pix& x) const;
    virtual T& operator()(Pix x) const;
};

template<class T>
Set<T>::Set()
{ }

template<class T>
Set<T>::Set(const Set& other)
{ }


template<class T>
class Set_DL: public List_DLS<T> {
public:
    Set_DL();
    Set_DL(const Set_DL& other);

    void add(const T& item)
	{ list.append(item); }
    void remove(Pix& x, T& item)
	{ list.remove(x, item); }

    void clear()
	{ list.clear(); }

    bool contains(const T& item) const
	{ return list.contains(item); }
    Pix search(const T& item) const
	{ return list.search(item); }

    unsigned length() const
	{ return list.length(); }

    Pix first() const
	{ return list.first(); }
    void next(Pix& x) const
	{ list.next(x); }
    T& operator()(Pix x) const
	{ return list(x); }
private:
    List_DLS<T> list;
};

template<class T>
class Set_DLp: public List_DLSp<T> {
public:
    Set_DLp();
    Set_DLp(const Set_DLp& other);

    void add(const T& item)
	{ list.append(item); }
    void remove(Pix& x, T& item)
	{ list.remove(x, item); }

    void clear()
	{ list.clear(); }

    bool contains(const T& item) const
	{ return list.contains(item); }
    Pix search(const T& item) const
	{ return list.search(item); }

    unsigned length() const
	{ return list.length(); }

    Pix first() const
	{ return list.first(); }
    void next(Pix& x) const
	{ list.next(x); }
    T& operator()(Pix x) const
	{ return list(x); }
private:
    List_DLSp<T> list;
};

template<class T>
struct vertex {
    T item;
    List_DL<vertex<T> *> fanout;

    vertex(): item(), fanout()	// { dg-bogus "" } 
      { };
    vertex(const T& i): item(), fanout() // { dg-bogus "" } 
      { };
};

template<class T>
class Graph {
public:
    Graph();
    Graph(const Graph&);
    ~Graph();

    void add(const T& from, const T& to);
    bool contains(const T& from, const T& to) const;

    void clear()
	{ vertices.clear(); }

    unsigned lengthV() const
	{ return vertices.length(); }

    Pix firstV() const
	{ return vertices.first(); }
    void nextV(Pix& x) const
	{ vertices.next(x); }
    T& V(Pix x) const
	{ return vertices(x).item; }

    Pix firstV1(Pix vx) const;
    void nextV1(Pix vx, Pix& x) const;
    T& V1(Pix vx, Pix x) const;
private:
    vertex<T> *lookup(const T& from) const;
    vertex<T> *lookup_new(const T& from);

    List_DLS<vertex<T> > vertices;
};

template<class T>
Graph<T>::Graph():
vertices()
{ }

template<class T>
Graph<T>::Graph(const Graph& other):
vertices()
{
    for (Pix vx=firstV(); 0 != vx; nextV(vx)) {
	for (Pix vx1=firstV1(vx); 0 != vx1; nextV1(vx, vx1)) {
	    add(V(vx), V1(vx, vx1));
	}
    }
}

template<class T>
Graph<T>::~Graph()
{
    clear();
}

template<class T>
void
Graph<T>::add(const T& from, const T& to)
{
    vertex<T> *fromv = lookup_new(from);
    if (from == to)
	return;
    vertex<T> *tov = lookup_new(to);
    fromv->fanout.append(tov);
}

template<class T>
bool
Graph<T>::contains(const T& from, const T& to) const
{
    vertex<T> *fromv = lookup(from);
    if (0 == fromv)
	return FALSE;

    for (Pix x=fromv->fanout.first(); 0 != x; fromv->fanout.next(x)) {
	if (fromv->fanout(x)->item == to)
	    return TRUE;
    }

    return FALSE;
}

template<class T>
vertex<T> *
Graph<T>::lookup(const T& from) const
{
    for (Pix x=vertices.first(); 0 != x; vertices.next(x)) {
	if (vertices(x).item == from)
	    return &vertices(x);
    }
    return 0;
}

template<class T>
vertex<T> *
Graph<T>::lookup_new(const T& from)
{
    vertex<T> *v = lookup(from);
    if (0 == v) {
	vertices.append(from);
	return &vertices(vertices.last());
    }
    return v;
}

template<class T>
Pix
Graph<T>::firstV1(Pix vx) const
{
    vertex<T> *v = (vertex<T> *) vx;
    return v->fanout.first();
}

template<class T>
void
Graph<T>::nextV1(Pix vx, Pix& x) const
{
    vertex<T> *v = (vertex<T> *) vx;
    return v->fanout.next(x);
}

template<class T>
T&
Graph<T>::V1(Pix vx, Pix x) const
{
    vertex<T> *v = (vertex<T> *) vx;
    static T x1;
    return x1;
}

class STRLIdentifier;

extern int x(List_DL<STRLIdentifier *>);
extern int x(List_DLS<STRLIdentifier *>);

extern int x(Set<STRLIdentifier *>);
extern int x(Set_DL<STRLIdentifier *>);
extern int x(Set_DLp<STRLIdentifier *>);

extern int x(Graph<STRLIdentifier *>);

class STRLIdentifier {
    char buf[10];
};

extern int operator==(vertex<STRLIdentifier*>&, vertex<STRLIdentifier*>&); // { dg-error "" } const subversion
extern int operator==(STRLIdentifier&, STRLIdentifier&); // { dg-error "" } fn ref in err msg

extern int x(List_DLSp<STRLIdentifier *>);

template class Graph<STRLIdentifier *>;
template class List_DLS<vertex<STRLIdentifier *> >;
