//////////////////////////////////////////////////////////////////////////////
// $Id: MAPITL_tmpl.h,v 1.1.1.3 2005/01/26 13:42:20 nthiery Exp $
// Name:	MAPITL_tmpl.h
// Purpose:	Template Library for the
//		MuPAD Application Programming Interface
//		(Templates implementation)
// Author:	Nicolas M. Thiéry <nthiery@mines.edu>
// Created:	2000/08
// Copyright:	LGPL
//////////////////////////////////////////////////////////////////////////////

#ifndef _MAPITL_TMPL_H
#define _MAPITL_TMPL_H

#include<stdexcept>
#include<string>
#include "MAPITL.h"
#include "MAPITL/Cell_tmpl.h"

//////////////////////////////////////////////////////////////////////////////
// Conversions C++ object -> MTcell
//////////////////////////////////////////////////////////////////////////////

//  template <>
//  MTcell& MAPITL::CtoM<> (MTcell &c) {
//    return c;
//  }

MTcell MAPITL::CtoM () {
  return MFcopy(MVnull);
}

MTcell MAPITL::CtoM (bool i) {
  return MFbool(i);
}

MTcell MAPITL::CtoM (char i) {
  return MFint(i);
}

MTcell MAPITL::CtoM (unsigned char i) {
  return MFint(i);
}

MTcell MAPITL::CtoM (short int i) {
  return MFint(i);
}

MTcell MAPITL::CtoM (unsigned int i) {
  return MFlong(long(i));
}

MTcell MAPITL::CtoM (long unsigned int i) {
  return MFlong(long(i));
}

MTcell MAPITL::CtoM (int i) {
  return MFint(i);
}

MTcell MAPITL::CtoM (long int i) {
  return MFlong(i);
}

MTcell MAPITL::CtoM (long long int i) { // Warning, possible loss of information!
  return MFlong( (long int) i);
}

MTcell MAPITL::CtoM (float f) {
  return MFfloat(f);
}

MTcell MAPITL::CtoM (double f) {
  return MFdouble(f);
}

MTcell MAPITL::CtoM (const string s) {
  return MFstring((char *)s.c_str());
}

// Specialization returning a handle to a pointer as a DOM_INT
MTcell MAPITL::CtoM (void *p) {
  return MFint(reinterpret_cast<size_t>(p));
}

template<class S, class T>
MTcell MAPITL::CtoM(std::pair<S,T> p) {
  MTcell l=MFnewList(2);
  MFsetList(&l, 0, MAPITL::CtoM(p.first));
  MFsetList(&l, 1, MAPITL::CtoM(p.second));
  MFsig(l);
  return l;
}

//////////////////////////////////////////////////////////////////////////////
// Iterators

// See Stroustrup C++ programming Language 3rd ed. p. 553 for the use
// of iterator traits to select the proper implementation.

// Implementation for any iterator (calls the proper helper function)
template<class Iterator>
MTcell MAPITL::CtoM(Iterator first, Iterator last) {
  return CtoM(first, last,
	      typename iterator_traits<Iterator>::iterator_category());
}

// Implementation for random access iterators (Helper function)
template<class RandomAccessIterator>
MTcell MAPITL::CtoM(RandomAccessIterator first, RandomAccessIterator last,
		    random_access_iterator_tag) {
  MTcell l=MFnewList(distance(first,last));
  size_t i=0;
  for(RandomAccessIterator it=first; it!=last; it++, i++) {
    MFsetList(&l, i, CtoM(*it));
  }
  MFsig(l);
  return l;
}

// Implementation for any input iterator (Helper function)
template<class InputIterator>
MTcell MAPITL::CtoM(InputIterator first, InputIterator last,
		    input_iterator_tag) {
  size_t i=0;
  MTcell l=MFnewList(0);
  for(InputIterator it=first; it!=last; it++, i++) {
    MFnopsList(&l, i+1);
    MFsetList(&l, i, CtoM(*it));
  }
  MFsig(l);
  return l;
}

//////////////////////////////////////////////////////////////////////////////
// Conversions MTcell -> C++ object
//////////////////////////////////////////////////////////////////////////////

bool MAPITL::MtoC(MTcell c, Type<bool>) {
  if(!MFisBool(c)) MFerror("Type error: DOM_BOOL expected");
  return MFbool(c);
}

int MAPITL::MtoC(MTcell c, Type<int>) {
  if(!MFisInt(c)) MFerror("Type error: DOM_INT expected");
  return MFint(c);
}

char MAPITL::MtoC(MTcell c, Type<char>) {
  return MtoC<int>(c);
}

unsigned char MAPITL::MtoC(MTcell c, Type<unsigned char>) {
  return MtoC<int>(c);
}

short int MAPITL::MtoC(MTcell c, Type<short int>) {
  return MtoC<int>(c);
}

unsigned int MAPITL::MtoC(MTcell c, Type<unsigned int>) {
  return MtoC<long>(c);
}

long unsigned int MAPITL::MtoC(MTcell c, Type<long unsigned int>) {
  return MtoC<long>(c);
}

long MAPITL::MtoC(MTcell c, Type<long>) {
  if(!MFisInt(c)) MFerror("Type error: DOM_INT expected");
  return MFlong(c);
}

float MAPITL::MtoC(MTcell c, Type<float>) {
  if(!MFisNumber(c)) MFerror("Type error: DOM_FLOAT expected");
  return MFfloat(c);
}

double MAPITL::MtoC(MTcell c, Type<double>) {
  if(!MFisNumber(c)) MFerror("Type error: DOM_FLOAT expected");
  return MFdouble(c);
}

std::string MAPITL::MtoC(MTcell c, Type<std::string>) {
  if(!MFisString(c)) MFerror("Type error: DOM_STRING expected");
  return string(MFstring(c));
}

void * MAPITL::MtoC(MTcell c, Type<void *>) {
  if(!MFisInt(c)) MFerror("Type error: DOM_INT expected");
  return reinterpret_cast<void *>(MFint(c));
}

template<class S, class T>
std::pair<S,T> MAPITL::MtoC(MTcell c, Type<std::pair<S,T> >) {
  S c1=MtoC<S>(MFgetList(&c,0));
  T c2=MtoC<T>(MFgetList(&c,1));
  return std::make_pair(c1,c2);
}

template<class C>
C MAPITL::MtoC(MTcell c, Type<C>) {
  switch(MFdom(c)) {
  case DOM_LIST: {
    C v(MFnopsList(c));
    size_t i=0;
    for(typename C::iterator it=v.begin(); it!=v.end(); it++, i++) {
      *it=MtoC<typename C::value_type>(MFgetList(&c, i));
    };
    return v;
  }
  case DOM_EXPR: {
    C v(MFnopsExpr(c));
    size_t i=0;
    for(typename C::iterator it=v.begin(); it!=v.end(); it++, i++) {
      *it=MtoC<typename C::value_type>(MFgetExpr(&c, i));
    };
    return v;
  }
  }
  MFerror("Type error: DOM_EXPR expected");
  return(C(0));
}

//////////////////////////////////////////////////////////////////////////////
// Container class
//////////////////////////////////////////////////////////////////////////////

template<class T>
const MTcell
MAPITL::Container<T>::cell() const {
  return c;
}

template<class T>
MTcell
MAPITL::Container<T>::cell() {
  return c;
}

template<class T>
bool
MAPITL::Container<T>::empty    () const { return MFnopsList(c)==0; }

template<class T>
typename MAPITL::Container<T>::size_type
MAPITL::Container<T>::size     () const { return MFnopsList(c);    }

template<class T>
typename MAPITL::Container<T>::size_type
MAPITL::Container<T>::capacity () const { return MFnopsList(c);;   }

template<class T>
typename MAPITL::Container<T>::value_type
MAPITL::Container<T>::operator[] (size_type i) const {
  return MtoC<T>(MFgetList(&c, i));
}

template<class T>
typename MAPITL::Container<T>::reference
MAPITL::Container<T>::operator[] (size_type i) {
  return Reference<T>(c,i);
}

template<class T>
void
MAPITL::Container<T>::check (size_type i) const {
  if (!(i>=0 && i<MFnopsList(c))) {
    throw std::out_of_range("MAPITL::Container");
  }
}

template<class T>
typename MAPITL::Container<T>::value_type
MAPITL::Container<T>::at (size_type i) const {
  check(i);
  return *this[i];
}

template<class T>
typename MAPITL::Container<T>::reference
MAPITL::Container<T>::at (size_type i) {
  check(i);
  return Reference<T>(&c,i);
}

template<class T>
typename MAPITL::Container<T>::iterator
MAPITL::Container<T>::begin  () {
  return iterator(c,0);
}

template<class T>
typename MAPITL::Container<T>::iterator
MAPITL::Container<T>::end    () {
  return iterator(c,MFnopsList(c));
}

template<class T>
typename MAPITL::Container<T>::const_iterator
MAPITL::Container<T>::begin  () const {
  return const_iterator(c,0);
}

template<class T>
typename MAPITL::Container<T>::const_iterator
MAPITL::Container<T>::end    () const {
  return const_iterator(c,MFnopsList(c));
}

template<class T>
typename MAPITL::Container<T>::reverse_iterator
MAPITL::Container<T>::rbegin () {
  return reverse_iterator(end());
}

template<class T>
typename MAPITL::Container<T>::reverse_iterator
MAPITL::Container<T>::rend   () {
  return reverse_iterator(begin());
}

template<class T>
typename MAPITL::Container<T>::const_reverse_iterator
MAPITL::Container<T>::rbegin () const {
  return const_reverse_iterator(end());
}

template<class T>
typename MAPITL::Container<T>::const_reverse_iterator
MAPITL::Container<T>::rend   () const {
  return const_reverse_iterator(begin());
}

template<class T>
MAPITL::Container<T> &
MAPITL::Container<T>::push_back(value_type t) {
  long n=MFnopsList(c);
  MFnopsList(&c, n+1);
  MFsetList (&c, n, CtoM(t));
  MFsig(c);
  return *this;
}
    
//////////////////////////////////////////////////////////////////////////////
// Iterator class
//////////////////////////////////////////////////////////////////////////////

template<class T>
typename MAPITL::Iterator<T>::value_type
MAPITL::Iterator<T>::operator *() const {
  return MtoC<T>(MFgetList(&c, i));
}

template<class T>
typename MAPITL::Iterator<T>::reference
MAPITL::Iterator<T>::operator *() {
  return Reference<T>(c, i);
}

template<class T>
typename MAPITL::Iterator<T>::const_pointer
MAPITL::Iterator<T>::operator ->() const {
  return new value_type(operator*());
}

template<class T>
MAPITL::Iterator<T> &
MAPITL::Iterator<T>::operator ++ () {
  ++i;  return *this;
}

template<class T>
MAPITL::Iterator<T> &
MAPITL::Iterator<T>::operator -- () {
  --i;  return *this;
}

template<class T>
MAPITL::Iterator<T>
MAPITL::Iterator<T>::operator ++ (int) {
  return Iterator(c,i++);
}

template<class T>
MAPITL::Iterator<T>
MAPITL::Iterator<T>::operator -- (int) {
  return Iterator(c,i++);
}

template<class T>
MAPITL::Iterator<T> &
MAPITL::Iterator<T>::operator += (difference_type n) {
  i+=n; return *this;
}

template<class T>
MAPITL::Iterator<T> &
MAPITL::Iterator<T>::operator -= (difference_type n) {
  i-=n; return *this;
}
    
template<class T>
bool
MAPITL::operator == (const MAPITL::Iterator<T> &it1, const MAPITL::Iterator<T> &it2) {
  return it1.i==it2.i;
}

template<class T>
bool
MAPITL::operator != (const MAPITL::Iterator<T> &it1, const MAPITL::Iterator<T> &it2) {
  return it1.i!=it2.i;
}

template<class T>
bool
MAPITL::operator <  (const MAPITL::Iterator<T> &it1, const MAPITL::Iterator<T> &it2) {
  return it1.i<it2.i;
}

template<class T>
bool
MAPITL::operator >  (const MAPITL::Iterator<T> &it1, const MAPITL::Iterator<T> &it2) {
  return it1.i>it2.i;
}

template<class T>
bool
MAPITL::operator <= (const MAPITL::Iterator<T> &it1, const MAPITL::Iterator<T> &it2) {
  return it1.i<=it2.i;
}

template<class T>
bool
MAPITL::operator >= (const MAPITL::Iterator<T> &it1, const MAPITL::Iterator<T> &it2) {
  return it1.i>=it2.i;
}

template<class T>
typename MAPITL::Iterator<T>::difference_type
MAPITL::operator -  (const MAPITL::Iterator<T> &it1, const MAPITL::Iterator<T> &it2) {
  return it1.i-it2.i;
}

//////////////////////////////////////////////////////////////////////////////
// Reference class
//////////////////////////////////////////////////////////////////////////////

template<class T>
MAPITL::Reference<T>::operator T() const {
  return MtoC<T>(MFgetList(&c, i));
}

template<class T>
const T *
MAPITL::Reference<T>::operator -> () const {
  return &T();
}

template<class T>
MAPITL::Reference<T> &
MAPITL::Reference<T>::operator =(const T &t) {
  MFsetList(&c, i, CtoM(t));
  //MFsig(c);
  return *this;
}

template<class T>
MAPITL::Reference<T> &
MAPITL::Reference<T>::operator =(const MAPITL::Reference<T>& t) {
  return(*this=T(t));
}

#endif	/* _MAPITL_TMPL_H */

// Local Variables: 
// mode: c++
// End:
