/**************************************************************************
**       Title: demo program for use of CRTP, the curiously recurring
**              template pattern for
**              separating interface and implementation
**        Date: 30.10.2008
**   Copyright: Bernard Haasdonk
**************************************************************************/

#include<iostream>
#include<vector>

using std::cout;
using std::endl;
using std::vector;

/**************************************************************************
**       Interface class with CRTP
**************************************************************************/
template <class VectorImp>
class VectorInterface
{
 public:

  // definition of interface methods and forwarding call to derived class:

  // set all entries
  inline void setAll(const double& val)
    {
      asImp().setAll(val);
    }
  
  // size method
  inline int size() const
    {
      return asImp().size();      
    }
  
  // print method
  inline void print()
    {
      asImp().print();      
    }

  // access by [i] with integer i for read and write
  inline double& operator[](int i)
    {
      return asImp().operator[](i);
    }
  
 protected:
  // asImp() for CRTP, const and non-const version
  inline const VectorImp &asImp() const 
    { 
      return static_cast< const VectorImp& >( *this );
    }
  
  inline VectorImp &asImp()  
    { 
      return static_cast< VectorImp& >( *this );
    }
}; 

/**************************************************************************
**       Default Implementation class 
**************************************************************************/
template <class VectorImp>
class DefaultVectorImplementation:
  public VectorInterface<VectorImp>
{
public:
  DefaultVectorImplementation(const int size):
    //  VectorInterface<VectorImp>(size), 
    size_(size)
  {
  }  

  // default implementation of size
  inline int size()
  {
    return size_;
  }

  // default implementation of print by calling interface methods
  inline void print()
  {
    cout << "size: " << size_ << ", elements: ";
    for (int i=0;i < size_;i++)
      cout << this->operator[](i) << " ";
    cout << endl;
  }

  // default implementation of setAll by calling interface methods
  inline void setAll(const double& val)
  {    
    for (int i=0; i < size() ; ++i)
      this->operator[](i) = val;
  }

    
private:
  int size_;

};

/**************************************************************************
**       Specific Implementation 1 based on stl-vector class
**************************************************************************/
class Vector1: public DefaultVectorImplementation<Vector1>
{
public:
  Vector1(const int size):
    DefaultVectorImplementation<Vector1>(size)
  {
    vec_.resize(size);
  }
  
  inline double& operator[](int i)
  {
    return vec_[i];
  }

  // if you want to overload default method, simply implement a new one:
  //inline void print()
  //{
  //  cout << "Vector1.print() method! " <<  endl;
  //  DefaultVectorImplementation<Vector1>::print();
  //}
  //
  //inline void setAll(const double& val)
  //{    
  //  for (int i=0; i < size() ; ++i)
  //	vec_[i] = val;
  //}
  
private:  
  vector<double> vec_;  
};

/**************************************************************************
**       Specific Implementation 2 based on double array
**************************************************************************/
class Vector2: public DefaultVectorImplementation<Vector2>
{
public:
  Vector2(const int size):
    DefaultVectorImplementation<Vector2>(size)
  {
    vec_ = new double[size];
  }
  
  ~Vector2()
  {
    delete[] vec_;
    vec_ = 0;
  }
    
  inline double& operator[](int i)
  {
    return vec_[i];
  }

  // if you want to overload default method, simply implement a new one:
  inline void setAll(const double& val)
  {    
    // get pointer to one-after-last element
    double* endit = vec_ + size();
    for (double* it= vec_; it!= endit; ++it)
      *it = val;
  }
  
private:
  double* vec_;
};


/**************************************************************************
**       Main Program  
**************************************************************************/

template <class VectorType>
void test_vector(int size, double value)
{
  VectorType vec(size);
  vec.print();
  vec.setAll(value);
  vec.print();
  vec[0] = vec[0] + 100.0;
  vec.print();
}

int main()
{
  test_vector<Vector1>(4,4.0);
  test_vector<Vector2>(8,8.0);
}