/*
 * This file is part of the Cforall project
 *
 * $Id: typeops.h,v 1.14 2005/08/29 20:14:17 rcbilson Exp $
 *
 */

#ifndef TYPEOPS_H
#define TYPEOPS_H

#include "SynTree/SynTree.h"
#include "SynTree/Type.h"
#include "SymTab/Indexer.h"
#include "Cost.h"
#include "TypeEnvironment.h"

namespace ResolvExpr {

// combos: takes a list of sets and returns a set of lists representing
// every possible way of forming a list by picking one element out of each set
template< typename InputIterator, typename OutputIterator >
void
combos( InputIterator begin, InputIterator end, OutputIterator out )
{
  typedef typename InputIterator::value_type SetType;
  typedef typename std::list< typename SetType::value_type > ListType;
  
  if( begin == end )
  {
    *out++ = ListType();
    return;
  }
  
  InputIterator current = begin;
  begin++;

  std::list< ListType > recursiveResult;
  combos( begin, end, back_inserter( recursiveResult ) );
  
  for( typename std::list< ListType >::const_iterator i = recursiveResult.begin(); i != recursiveResult.end(); ++i ) {
    for( typename ListType::const_iterator j = current->begin(); j != current->end(); ++j ) {
      ListType result;
      std::back_insert_iterator< ListType > inserter = back_inserter( result );
      *inserter++ = *j;
      std::copy( i->begin(), i->end(), inserter );
      *out++ = result;
    }
  }
}
  
// in AdjustExprType.cc
void adjustExprType( Type *&type, const TypeEnvironment &env, const SymTab::Indexer &indexer );

template< typename ForwardIterator >
void
adjustExprTypeList( ForwardIterator begin, ForwardIterator end, const TypeEnvironment &env, const SymTab::Indexer &indexer )
{
  while( begin != end ) {
    adjustExprType( *begin++, env, indexer );
  }
}

// in CastCost.cc
Cost castCost( Type *src, Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env );

template< typename SrcIterator, typename DestIterator >
Cost
castCostList( SrcIterator srcBegin, SrcIterator srcEnd, DestIterator destBegin, DestIterator destEnd, const SymTab::Indexer &indexer, const TypeEnvironment &env )
{
  Cost ret;
  if( destBegin == destEnd ) {
    if( srcBegin == srcEnd ) {
      return Cost::zero;
    } else {
      return Cost( 0, 0, 1 );
    }
  }
  while( srcBegin != srcEnd && destBegin != destEnd ) {
    Cost thisCost = castCost( *srcBegin++, *destBegin++, indexer, env );
    if( thisCost == Cost::infinity ) {
      return Cost::infinity;
    }
    ret += thisCost;
  }
  if( srcBegin == srcEnd && destBegin == destEnd ) {
    return ret;
  } else {
    return Cost::infinity;
  }
}

// in ConversionCost.cc
Cost conversionCost( Type *src, Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env );

template< typename SrcIterator, typename DestIterator >
Cost
conversionCostList( SrcIterator srcBegin, SrcIterator srcEnd, DestIterator destBegin, DestIterator destEnd, const SymTab::Indexer &indexer, const TypeEnvironment &env )
{
  Cost ret;
  while( srcBegin != srcEnd && destBegin != destEnd ) {
    Cost thisCost = conversionCost( *srcBegin++, *destBegin++, indexer, env );
    if( thisCost == Cost::infinity ) {
      return Cost::infinity;
    }
    ret += thisCost;
  }
  if( srcBegin == srcEnd && destBegin == destEnd ) {
    return ret;
  } else {
    return Cost::infinity;
  }
}

// in PtrsAssignable.cc
int ptrsAssignable( Type *src, Type *dest, const TypeEnvironment &env );

// in PtrsCastable.cc
int ptrsCastable( Type *src, Type *dest, const TypeEnvironment &env, const SymTab::Indexer &indexer );

// in Unify.cc
bool typesCompatible( Type *, Type *, const SymTab::Indexer &indexer, const TypeEnvironment &env );
bool typesCompatibleIgnoreQualifiers( Type *, Type *, const SymTab::Indexer &indexer, const TypeEnvironment &env );

inline bool typesCompatible( Type *t1, Type *t2, const SymTab::Indexer &indexer )
{
  TypeEnvironment env;
  return typesCompatible( t1, t2, indexer, env );
}

inline bool typesCompatibleIgnoreQualifiers( Type *t1, Type *t2, const SymTab::Indexer &indexer )
{
  TypeEnvironment env;
  return typesCompatibleIgnoreQualifiers( t1, t2, indexer, env );
}

template< typename Container1, typename Container2 >
bool
typesCompatibleList( Container1 &c1, Container2 &c2, const SymTab::Indexer &indexer, const TypeEnvironment &env )
{
  typename Container1::iterator i1 = c1.begin();
  typename Container2::iterator i2 = c2.begin();
  for( ; i1 != c1.end() && i2 != c2.end(); ++i1, ++i2 ) {
    if( !typesCompatible( *i1, *i2, indexer ) ) {
      return false;
    }
  }
  return ( i1 == c1.end() ) && ( i2 == c2.end() );
}

// in CommonType.cc
Type *commonType( Type *type1, Type *type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars );

// in PolyCost.cc
int polyCost( Type *type, const TypeEnvironment &env, const SymTab::Indexer &indexer );

// in Occurs.cc
bool occurs( Type *type, std::string varName, const TypeEnvironment &env );

} // namespace ResolvExpr

#endif /* #ifndef TYPEOPS_H */
