/*
 * This file is part of the Cforall project
 *
 * Some useful template utility functions
 *
 * $Id: utility.h,v 1.17 2003/11/26 18:05:21 rgesteve Exp $
 *
 */

#ifndef COMMON_UTILITY_H
#define COMMON_UTILITY_H

#include <iostream>
#include <strstream>
#include <iterator>
#include <string>
#include <cctype>
#include <list>

template< typename T >
static inline T*
maybeClone( const T *orig )
{
  if( orig ) {
    return orig->clone();
  } else {
    return 0;
  }
}

template< typename T, typename U >
static inline T*
maybeBuild( const U *orig )
{
  if( orig ) {
    return orig->build();
  } else {
    return 0;
  }
}

template< typename Input_iterator >
void
printEnums( Input_iterator begin, Input_iterator end, const char * const *name_array, std::ostream &os )
{
  for( Input_iterator i = begin; i != end; ++i ) {
    os << name_array[ *i ] << ' ';
  }
}

template< typename Container >
void
deleteAll( Container &container )
{
  for( typename Container::iterator i = container.begin(); i != container.end(); ++i ) {
    delete *i;
  }
}

template< typename Container >
void
printAll( const Container &container, std::ostream &os, int indent = 0 )
{
  for( typename Container::const_iterator i = container.begin(); i != container.end(); ++i ) {
    if( *i ) {
      os << std::string(indent,  ' ');
      (*i)->print( os, indent + 2 );
      os << std::endl;
    }
  }
}

template< typename SrcContainer, typename DestContainer >
void
cloneAll( const SrcContainer &src, DestContainer &dest )
{
  typename SrcContainer::const_iterator in = src.begin();
  std::back_insert_iterator< DestContainer > out( dest );
  while( in != src.end() ) {
    *out++ = (*in++)->clone();
  }
}

template< typename Container >
void
assertAll( const Container &container )
{
  int count = 0;
  for( typename Container::const_iterator i = container.begin(); i != container.end(); ++i ) {
    if( !(*i) ) {
      std::cerr << count << " is null" << std::endl;
    }
  }
}

static inline std::string
assign_strptr( std::string *str )
{
  if( str == 0 ) {
    return "";
  } else {
    std::string tmp;
    tmp = *str;
    delete str;
    return tmp;
  }
}

template< class T, typename ResultType, ResultType (T::* memfunc)() >
ResultType dispatch(T *pT){
  return (pT->*memfunc)();
}

template < typename T >
std::list<T> tail( std::list<T> l )
{
  if(! l.empty()){
    std::list<T> ret(++(l.begin()), l.end());
    return ret;
  }
}

template < typename T >
std::list<T> flatten( std::list < std::list<T> > l) {
  typedef std::list <T> Ts;

  Ts ret;

  switch( l.size() ){
  case 0:
    return ret;
  case 1:
    return l.front();
  default:
    ret = flatten(tail(l));
    ret.insert(ret.begin(), l.front().begin(), l.front().end());
    return ret;
  }
}

template < typename T > 
std::string toString ( T value ) {
  std::ostrstream os;
  
  os << value; // << std::ends;
  os.freeze( false );

  return std::string(os.str(), os.pcount());
}

template< class Constructed, typename Arg >
Constructed *ctor( Arg arg ) {
  Constructed *c = new Constructed( arg );
  return c;
}

template< class Constructed, typename Arg >
Constructed ctor_noptr( Arg arg ) {
  return Constructed( arg );
}

template< typename T >
void replace( std::list< T > &org, typename std::list< T >::iterator pos, std::list< T > &with ) {
  // TIter should secretly be a typename std::list< T >::iterator
  //   ( g++ 3.2 issues a 'is implicitly a typename' warning if I make this explicit )
   typename std::list< T >::iterator next = pos; advance( next, 1 );

   //if ( next != org.end() ) {
    org.erase( pos );
    org.splice( next, with );
    //}

  return;
}

template< typename T1, typename T2 >
T2 *cast_ptr( T1 *from ) {
  return dynamic_cast< T2 * >( from );
}

template< class Exception, typename Arg >
void inline assert_throw( bool pred, Arg arg ) {
  if (pred) throw Exception( arg );
}

template< typename T >
struct is_null_pointer {
  bool operator()( const T *ptr ){ return ( ptr == 0 ); }
};

template< class InputIterator, class OutputIterator, class Predicate >
void filter(InputIterator begin, InputIterator end, OutputIterator out, Predicate pred)
{
  while ( begin++ != end )
    if( pred(*begin) ) *out++ = *begin;

  return;
}

template< class InputIterator1, class InputIterator2, class OutputIterator >
void zip( InputIterator1 b1, InputIterator1 e1, InputIterator2 b2, InputIterator2 e2, OutputIterator out ) {
  while( b1 != e1 && b2 != e2 )
    *out++ = std::pair<typename InputIterator1::value_type, typename InputIterator2::value_type>(*b1++, *b2++);
}

template< class InputIterator1, class InputIterator2, class OutputIterator, class BinFunction >
void zipWith( InputIterator1 b1, InputIterator1 e1, InputIterator2 b2, InputIterator2 e2, OutputIterator out, BinFunction func ) {
  while( b1 != e1 && b2 != e2 )
    *out++ = func(*b1++, *b2++);
}

#endif /* #ifndef COMMON_UTILITY_H */

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