#if !defined(__MIMASINTERNALARRAYFUNC)
#   error "Do not include this file directly."
#endif
#if !defined(__MIMASEXTERNALARRAYFUNC)
#   error "Do not include this file directly."
#endif
#if !defined(__MIMASFUNCTIONOBJECT)
#   error "Do not include this file directly."
#endif

namespace mimas {

/** @addtogroup arrayOp
    @{ */
///
template <
  template< typename, size_t, typename > class MultiArray1,
  template< typename, size_t, typename > class MultiArray2,
  typename T, size_t NumDims, typename Allocator
>
boost::multi_array< T, NumDims, Allocator > __MIMASEXTERNALARRAYFUNC
( const MultiArray1< T, NumDims, Allocator > &a,
  const MultiArray2< T, NumDims, Allocator > &b )
{
  return multi_func< T >( a, b, __MIMASFUNCTIONOBJECT< T >() );
};

///
template <
  template< typename, size_t, typename > class MultiArray,
  typename T, size_t NumDims, typename Allocator
>
boost::multi_array< T, NumDims, Allocator > __MIMASEXTERNALARRAYFUNC
( const MultiArray< T, NumDims, Allocator > &a,
  const T &b )
{
  return multi_func< T >( a, std::bind2nd( __MIMASFUNCTIONOBJECT< T >(), b ) );
};

///
template <
  template< typename, size_t, typename > class MultiArray,
  typename T, size_t NumDims, typename Allocator
>
boost::multi_array< T, NumDims, Allocator > __MIMASEXTERNALARRAYFUNC
( const T &a,
  const MultiArray< T, NumDims, Allocator > &b )
{
  return multi_func< T >( b, std::bind1st( __MIMASFUNCTIONOBJECT< T >(), a ) );
};

///
template <
  template< typename, size_t, typename > class MultiArray2,
  typename T, size_t NumDims, typename Allocator
>
boost::detail::multi_array::sub_array< T, NumDims > __MIMASINTERNALARRAYFUNC
( boost::detail::multi_array::sub_array< T, NumDims > a,
  const MultiArray2< T, NumDims, Allocator > &b )
{
  return multi_apply( a, a, b,
                      _multi_help2< T, T, T, __MIMASFUNCTIONOBJECT< T > >
                        ( __MIMASFUNCTIONOBJECT< T >() ) );
};

///
template <
  template< typename, size_t, typename > class MultiArray1,
  template< typename, size_t, typename > class MultiArray2,
  typename T, size_t NumDims, typename Allocator
>
MultiArray1< T, NumDims, Allocator > &__MIMASINTERNALARRAYFUNC
( MultiArray1< T, NumDims, Allocator > &a,
  const MultiArray2< T, NumDims, Allocator > &b )
{
  return multi_apply( a, a, b,
                      _multi_help2< T, T, T, __MIMASFUNCTIONOBJECT< T > >
                      ( __MIMASFUNCTIONOBJECT< T >() ) );
};

///
template <
  typename T, size_t NumDims
>
boost::detail::multi_array::sub_array< T, NumDims > __MIMASINTERNALARRAYFUNC
( boost::detail::multi_array::sub_array< T, NumDims > a,
  const T &b )
{
  return multi_apply( a, a,
                      _multi_help1< T, T,
                          std::binder2nd< __MIMASFUNCTIONOBJECT< T > > >
                      ( std::bind2nd( __MIMASFUNCTIONOBJECT< T >(), b ) ) );
};

///
template <
  template< typename, size_t, typename > class MultiArray,
  typename T, size_t NumDims, typename Allocator
>
MultiArray< T, NumDims, Allocator > &__MIMASINTERNALARRAYFUNC
( MultiArray< T, NumDims, Allocator > &a,
  const T &b )
{
  return multi_apply( a, a,
                      _multi_help1< T, T,
                          std::binder2nd< __MIMASFUNCTIONOBJECT< T > > >
                      ( std::bind2nd( __MIMASFUNCTIONOBJECT< T >(), b ) ) );
};
///@}

}

#undef __MIMASINTERNALARRAYFUNC
#undef __MIMASEXTERNALARRAYFUNC
#undef __MIMASFUNCTIONOBJECT