// From mwg@csd.uwo.ca  Mon Apr 19 15:45:58 1999
// Received: from chaplin.csd.uwo.ca (chaplin.csd.uwo.ca [129.100.10.252])
// 	by eos00mh.eos.ncsu.edu (8.8.7/8.8.7) with ESMTP id PAA12479
// 	for <kaltofen@eos.ncsu.edu>; Mon, 19 Apr 1999 15:45:57 -0400 (EDT)
// Message-Id: <199904191945.PAA10592@heffalump.csd.uwo.ca>
// Date: Mon, 19 Apr 1999 15:45:42 -0400
// From: Mark Giesbrecht <mwg@csd.uwo.ca>
// MIME-Version: 1.0
// Content-Type: text/plain; charset=us-ascii
// Content-Transfer-Encoding: 7bit
// To: "Erich Kaltofen" <kaltofen@eos.ncsu.edu>
// Subject: code review and new code
// In-Reply-To: <9904071522.ZM344@eos.ncsu.edu>
// X-Mailer: VM 6.22 under 19.15 XEmacs Lucid
// X-UIDL: 77a7f73008d34574880fcdd1a3bf6e5e
// Status: OR
// 
// 
// Hi Erich,
// 
// Here are some comments on your traits code and some code of my own to
// attempt to address my concerns (not entirely successful).
// 
// Things which bother me:
// - I find that carrying around two objects (the data object F5 and the
//   traits object F5_trait) rather cumbersome (though I agree there are clearly
//   some advantages to making the interface objectless).  I've attempted
//   to address this by "hiding" the object through templatized
//   inheritance (not perfect, but...)
// - related to this (but distinct) is passing the field_traits object as
//   a parameter. I would argue that add, multiply, etc. are naturally methods of
//   field and should be invoked as such. 
// - re. using overloading and an additional "dummy" parameter to do
//   method selection (i.e., in specialized_add).  Clearly this works
//   but can now be done more cleanly with template partial
//   specialization (at least in theory - partial specialization of
//   template functions does not appear complete in the gnu compilers,
//   though partial specializations of classes works well).  The only
//   content of the parameter is its type and thus it is naturally a
//   template (class) parameter.
//   I used template partial-specialization (of classes) to do selection
//   in my code.
// 
// Related specifically to your code:
// - the "new"s cause potential performance problems (call to the memory
//   manager can't be inlined by some compilers).  I think 3 address
//   methods are better, at least for low level methods.
// - the pointer in the specialized_add for parameterized fields is hard
//   on performance. Compilers will not inline the add method
//   through the pointer.
//  
// Anyway, I enjoyed playing with your code and look forward to your
// comments on mine.
// 
// Mark
// 
// Here is a slightly different take on the field interface.
// Comments:
// - using templatized inheritance with virtual base class.  This puts one copy
//   of the object at the base of the heirarchy and gives some semblance of
//   an "objectless" interface a la Java.  I believe it is cleaner than the
//   user of a field having to declare two objects (traits and data).
// - add, subtract, ... are methods of the field, not globally exposed functions
// - using template partial specialization for selection of methods using traits
//   This is more natural than using dummy parameters with only type information
//   (though it is not as well supported by current compilers)
// - Everything conceivable can be inlined here - no pointers or calls to new
//
// Compiles with gcc version egcs-2.91.66 19990314 (egcs-1.1.2 release)
// (Experimental GNU Compiler: Available free from Cygnus: www.egcs.com)

#include <iostream>

// set of all possible field traits
class field_traits_list {
public:
  class parameterized {};
  class unparameterized {};
};
  
// default field traits to a parameterized field.
template <class K> 
class field_traits {
public:
  typedef typename K::element element;
  typedef field_traits_list::parameterized parameterization;
};

// template for generic fields.  Second parameter defaults to parameterization

template <class I>
class Interface {
protected:
  mutable I This;
};


// default field class.  Never expanded but selects second parameter
template <class K, class P=field_traits<K>::parameterization>
class field : virtual public Interface<K> {};

// template for parameterized field
template <class K>
class field<K,field_traits_list::parameterized> 
  : virtual public Interface<K> {
    
public:
  typedef field_traits<K>::element element;    
    
  field() {}
  template <class C1> field(C1 a1) { This=K(a1); }
  template <class C1, class C2> field(C1 a1, C2 a2) { This=K(a1,a2); }
    
  // access to the object is done via the () operator
  K& operator() () const { return This; }
  K& operator() () { return This; }

  void add(element& x, const element& y, const element& z) const {
    This.add(x,y,z);
  }  
};

template <class K>
class field<K,field_traits_list::unparameterized> 
  : virtual public Interface<K> {
public:
  typedef K element;    

  field() {}
  template <class C1> field(C1 a1) { This=K(a1); }
  template <class C1, class C2> field(C1 a1, C2 a2) { This=K(a1,a2); }

  K& operator() () const { return This; }
  K& operator() () { return This; }

  void add(element& x, const element& y, const element& z) const {
    x=y+z;
  }  
};

// integers modulo a small (int) prime
class Z_p {
public:
  int modulus; // modulus is stored in the field object
  Z_p (int m = 2) : modulus(m) {}
  
  // encapsulated element type
  class element {
  public:
    int residue; 
    template <class Field> 
    element(const Field& F, int start=0)
      {
	residue = start % F().modulus;
	if (residue < 0)
	  residue = residue + F().modulus;
      }
  }; // end class element
  
  element& add(element& x, const element& y, const element& z) const
    {
      x.residue = ( y.residue + z.residue ) % modulus;
      return x;
    }
}; // end class Z_p

ostream& operator<<(ostream& os, field<Z_p>::element& x) {
  os << x.residue << " (mod  something)" << endl;
  return os;
}



/* 

// This would override the add method of field<Z_p>.
// One could imagine having a default implementation (say repeated
// squaring for exponentiation) which might be completely overridden
// on specific domains.

template <>
void field<Z_p>::add(field<Z_p>::element& x, 
                     const field<Z_p>::element& y, 
                     const field<Z_p>::element& z) const {
  cout << "Specialized add" << endl;
  This.add(x,y,z);
}

*/

template <>
class field_traits<double> {
   typedef field_traits_list::unparameterized parameterization;
};

template <> 
class field_traits< field<double> > {
  typedef double element;
  typedef field_traits_list::unparameterized parameterization;
};

template<class Field>
typename Field::element& special_construct(const Field& F, int i,
                                           field_traits_list::parameterized dummy)
{return *new typename Field::element(F, i);
}

template<class Field>
typename Field::element& special_construct(const Field& F, int i,
                                           field_traits_list::unparameterized dummy)
{return *new typename Field::element(i);
}

template<class Field>
typename Field::element& generic_construct(const Field& F, int i)
{typename field_traits<Field>::parameterization dummy;
 return special_construct(F, i, dummy);
}

template<class Field>
void foo(const Field& F, int i)
{typename Field::element& x = generic_construct(F, i);
 cout << "foo(" << i << ")=" << x << endl;
}

int main(void)
{
  field<Z_p> F5(5); // F is integers modulo 5
  Z_p::element x(F5,4), y(F5,3), z(F5);

  field<double> R;
  field<double>::element a=4, b=5, c;

  F5.add(z,x,y);
  cout << "Z_p add: " <<  z << endl;
  R.add(c,a,b);
  cout << "R add" << c << endl;

  foo(F5, 3);
  foo(R, 3);
}

