// list_components.h        -*-C++-*-
// -------------------------------------------------------
// Algorithm Library Design, Juha K"arkk"ainen, 06/06/2003
// The components of the generative list example described in
//   "Generative Programming: Methods, Tools, and Applications"
//   by Krzysztof Czarnecki and Ulrich W. Eisenecker
//   Addison-Wesley, 2000
// with minor changes.

#include <cassert>
#include <typeinfo>
#include <iostream>

//----------------------------------------------------------------------
// PtrList
//----------------------------------------------------------------------
template <class Config_>
class PtrList
{
public:
  // export Config
  typedef Config_ Config;
  
private:
  // retrieve the needed types from the repository
  typedef typename Config::ElementType          ElementType;
  typedef typename Config::ElementArgumentType  ElementArgumentType;
  typedef typename Config::Copier               Copier;
  typedef typename Config::Destroyer            Destroyer;
  typedef typename Config::TypeChecker          TypeChecker;
  typedef typename Config::FinalListType        FinalListType;

  // data members
  ElementType*   head_;
  FinalListType* tail_;   // note: not PtrList* but FinalListType*

public:

  PtrList (ElementArgumentType& h, FinalListType *t = 0)
    : head_(0), tail_(t) { set_head(h); }

  ~PtrList() { Destroyer::destroy(head_); }

  void set_head(ElementArgumentType& h) {
    TypeChecker::check(h);
    head_ = Copier::copy(h);
  }

  ElementType& head() { return *head_; }

  void set_tail(FinalListType *t) { tail_ = t; }

  FinalListType* tail() const { return tail_; }

};


//----------------------------------------------------------------------
// Destroyers
//----------------------------------------------------------------------

template <class ElementType>
struct ElementDestroyer {
  static void destroy(ElementType* e) { delete e; }
};

template <class ElementType>
struct EmptyDestroyer {
  static void destroy(ElementType* e) {}
};

//----------------------------------------------------------------------
// TypeCheckers
//----------------------------------------------------------------------

template <class ElementType>
struct DynamicTypeChecker {
  static void check(const ElementType& e) { 
    assert(typeid(e)==typeid(ElementType));
  }
};

template <class ElementType>
struct EmptyTypeChecker {
  static void check(const ElementType& e) {}
};

//----------------------------------------------------------------------
// Copiers
//----------------------------------------------------------------------

template <class ElementType>
struct EmptyCopier {
  static ElementType* copy(ElementType& e) { return &e; }
};

template <class ElementType>
struct PolymorphicCopier {
  static ElementType* copy(const ElementType& e) { 
    return e.clone(); 
  }
};

template <class ElementType>
struct MonomorphicCopier {
  static ElementType* copy(const ElementType& e) { 
    return new ElementType(e);
  }
};

//----------------------------------------------------------------------
// LengthList
//----------------------------------------------------------------------
template <class BasicList>
class LengthList : public BasicList
{
public:
  // export config
  typedef typename BasicList::Config Config;

private:
  // retrieve the needed types from the repository
  typedef typename Config::ElementType          ElementType;
  typedef typename Config::ElementArgumentType  ElementArgumentType;
  typedef typename Config::LengthType           LengthType;
  typedef typename Config::FinalListType        FinalListType;

  LengthType length_;

  LengthType compute_length() const {
    return tail() ? tail()->length()+1 : 1;
  }

public:

  LengthList (ElementArgumentType& h, FinalListType *t = 0)
    : BasicList(h, t) {
    length_ = compute_length();
  }

  void set_tail(FinalListType *t) {
    BasicList::set_tail(t);
    length_ = compute_length();
  }

  LengthType length() const { return length_; }

};


//----------------------------------------------------------------------
// TracedList
//----------------------------------------------------------------------
template <class OptCounterList>
class TracedList : public OptCounterList
{
public:
  typedef typename OptCounterList::Config Config;

private:
  typedef typename Config::ElementType          ElementType;
  typedef typename Config::ElementArgumentType  ElementArgumentType;
  typedef typename Config::FinalListType        FinalListType;

  std::ostream& trace_stream() { return std::clog << "trace: "; }

public:
  TracedList (ElementArgumentType& h, FinalListType *t = 0)
    : OptCounterList(h, t) {
    trace_stream() << "construct(" << h << ")" << std::endl;
  }
  
  void set_head(ElementArgumentType& h) {
    trace_stream() << "set_head(" << h << ")" << std::endl;
    OptCounterList::set_head(h);
  }

  ElementType& head() { 
    trace_stream() << "head() = " << OptCounterList::head() << std::endl;
    return OptCounterList::head();
  }
};


