// list_example.C
// -------------------------------------------------------
// Algorithm Library Design, Juha K"arkk"ainen, 06/06/2003
// Test program for the list generator in list_generator.h

#include "list_generator.h"
#include <iostream>
#include <string>

// a class hierarchy for testing
struct Shape {
  virtual std::string name() const { return "Shape"; }
  virtual ~Shape() {}
  virtual Shape* clone() const { return new Shape(*this); }
};
struct Circle : public Shape {
  std::string name() const { return "Circle"; }
  Shape* clone() const { return new Circle(*this); }
};
struct Square : public Shape {
  std::string name() const { return "Square"; }
  Shape* clone() const { return new Square(*this); }
};
std::ostream& operator<< (std::ostream& s, const Shape& x) {
  return s << x.name();
}


// some help functions
template <class List>
void print_list(List* l) {
  std::cout << "[ ";
  for ( ; l; l = l->tail() ) std::cout << l->head() << " ";
  std::cout << "]\n";
}

template <class List>
void push_front(typename List::Config::ElementArgumentType& e, List*& l) {
  l = new List(e, l);
}


// manual configuration of a list type
struct Config1 {
  typedef int                             ElementType;
  typedef const ElementType               ElementArgumentType;
  typedef MonomorphicCopier<ElementType>  Copier;
  typedef ElementDestroyer<ElementType>   Destroyer;
  typedef DynamicTypeChecker<ElementType> TypeChecker;

  typedef TracedList<PtrList<Config1> >   FinalListType;
};

int main()
{
  typedef Config1::FinalListType ListType1;
  ListType1* list1 = 0;
  push_front(1, list1);
  push_front(2, list1);
  push_front(3, list1);
  print_list(list1);

  typedef LIST_GENERATOR<int,cp,mono,no_counter,with_tracing>::RET ListType2;
  ListType2* list2 = 0;
  push_front(1, list2);
  push_front(2, list2);
  push_front(3, list2);
  print_list(list2);

  typedef LIST_GENERATOR<int,ext_ref,mono,with_counter>::RET ListType3;
  int a[] = { 1, 2, 3 };
  ListType3* list3 = 0;
  push_front(a[2], list3);
  push_front(a[1], list3);
  push_front(a[0], list3);
  push_front(a[2], list3);
  print_list(list3);
  std::cout << "length=" << list3->length() << std::endl;

  typedef LIST_GENERATOR<Shape,cp,poly>::RET ListType4;
  ListType4* list4 = 0;
  push_front(Square(), list4);
  push_front(Circle(), list4);
  push_front(Shape(), list4);
  print_list(list4);

  typedef LIST_GENERATOR<Shape,cp,mono,no_counter,with_tracing>::RET 
    ListType5;
  ListType5* list5 = 0;
  push_front(Shape(), list5);
  print_list(list5);
  push_front(Circle(), list5);  // runtime error: wrong type
                                // for monomorphic list

}

