//============================================================================
//  The contents of this file are covered by the Viskores license. See
//  LICENSE.txt for details.
//
//  By contributing to this file, all contributors agree to the Developer
//  Certificate of Origin Version 1.1 (DCO 1.1) as stated in DCO.txt.
//============================================================================

$# vim: ft=python.cpp foldmethod=marker
//============================================================================
//  Copyright (c) Kitware, Inc.
//  All rights reserved.
//  See LICENSE.txt for details.
//
//  This software is distributed WITHOUT ANY WARRANTY; without even
//  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
//  PURPOSE.  See the above copyright notice for more information.
//============================================================================
//$# This file uses the pyexpander macro processing utility to build the
//$# FunctionInterface facilities that use a variable number of arguments.
//$# Information, documentation, and downloads for pyexpander can be found at:
//$#
//$#     http://pyexpander.sourceforge.net/
//$#
//$# To build the source code, execute the following (after installing
//$# pyexpander, of course):
//$#
//$#     expander.py VecOperators.h.in > VecOperators.h
//$#
//$# Ignore the following comment. It is meant for the generated file.
// **** DO NOT EDIT THIS FILE!!! ****
// This file is automatically generated by VecOperators.h.in
// clang-format off
#ifndef viskores_internal_VecOperators_h
#define viskores_internal_VecOperators_h

#include <viskores/internal/Configure.h>

namespace viskores {

#if (!(defined(VISKORES_CUDA) && (__CUDACC_VER_MAJOR__ < 8)))
#if (defined(VISKORES_GCC) || defined(VISKORES_CLANG))
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
#pragma GCC diagnostic ignored "-Wpragmas"
#pragma GCC diagnostic ignored "-Wconversion"
#pragma GCC diagnostic ignored "-Wfloat-conversion"
#endif // gcc || clang
#endif // not using cuda < 8

#if defined(VISKORES_MSVC)
#pragma warning(push)
#pragma warning(disable : 4244)
#endif


$py(
max_size = 4
operators = ['+', '*', '-', '/']
operands = {
    "Vec_Vec" : [['T', 'T']],
    "Vec_Scalar" : [['T', 'T'], ['T', "viskores::Float64"], ["viskores::Float64", "viskores::Float64"]],
    "Scalar_Vec" : [['T', 'T'], ['T', "viskores::Float64"], ["viskores::Float64", "viskores::Float64"]]
}
)\
\
// operator- unary overloads for generic and specific sizes {{{
template <typename T, viskores::IdComponent Size>
inline VISKORES_EXEC_CONT
typename std::enable_if<(std::is_floating_point<T>::value || std::is_signed<T>::value),
                        viskores::Vec<T, Size>>::type
operator-(viskores::Vec<T, Size> x)
{
  for(int i=0; i < Size; ++i)
  {
      x[i] = -x[i];
  }
  return x;
}

$for(SIZE in range(1, max_size+1))\
template <typename T>
inline VISKORES_EXEC_CONT
typename std::enable_if<(std::is_floating_point<T>::value || std::is_signed<T>::value),
                        viskores::Vec<T, $(SIZE)>>::type
operator-(const viskores::Vec<T, $(SIZE)>& x)
{
    return viskores::Vec<T, $(SIZE)>(\
$for(i in range(0, SIZE))\
\
$# Trailing comma between arguments
$if(i != 0)\
, \
$endif\
\
-x[$(i)]\
\
$endfor\
);
}

$endfor\

//}}}

$for(OPERATOR in operators)\
// operator$(OPERATOR) overloads for generic vector sizes -------------------{{{
$for((PARAMETERS, types) in operands.items())\
$for(TYPE in types)\
\
// $(PARAMETERS) for $(TYPE)
$if(TYPE[0] == "viskores::Float64")\
template <IdComponent Size>
$else\
template <typename T, IdComponent Size>
$endif\
inline VISKORES_EXEC_CONT viskores::Vec<$(TYPE[0]), Size> operator$(OPERATOR)(
$if(PARAMETERS == "Vec_Vec")\
    viskores::Vec<$(TYPE[0]), Size> a, const viskores::Vec<$(TYPE[1]), Size>& b
$elif(PARAMETERS == "Vec_Scalar")\
    viskores::Vec<$(TYPE[0]), Size> a, $(TYPE[1]) scalar
$else\
    $(TYPE[1]) scalar, viskores::Vec<$(TYPE[0]), Size> a
$endif\
)
{
  for (int i = 0; i < Size; ++i)
  {
$if(PARAMETERS == "Vec_Vec")\
    a[i] = a[i] $(OPERATOR) b[i];
$elif(PARAMETERS == "Vec_Scalar")\
    a[i] = a[i] $(OPERATOR) scalar;
$else\
    a[i] = scalar $(OPERATOR) a[i];
$endif\
  }
  return a;
}

$endfor\
$endfor\
//}}}
$endfor\

$for(OPERATOR in operators)\
// operator$(OPERATOR) overloads for specific vector sizes -------------------{{{
$for(SIZE in range(1, max_size+1))\
$for((PARAMETERS, types) in operands.items())\
$for(TYPE in types)\
\
// $(PARAMETERS) for $(TYPE)
$# No need for templates when all parameters are not templated
$if(TYPE[0] != "viskores::Float64")\
template <typename T>
$endif\
inline VISKORES_EXEC_CONT viskores::Vec<$(TYPE[0]), $(SIZE)> operator$(OPERATOR)(
$if(PARAMETERS == "Vec_Vec")\
    const viskores::Vec<$(TYPE[0]), $(SIZE)>& a, const viskores::Vec<$(TYPE[1]), $(SIZE)>& b
$elif(PARAMETERS == "Vec_Scalar")\
    const viskores::Vec<$(TYPE[0]), $(SIZE)>& a, $(TYPE[1]) scalar
$else\
    $(TYPE[1]) scalar, const viskores::Vec<$(TYPE[0]), $(SIZE)>& a
$endif\
)
{
  return viskores::Vec<$(TYPE[0]), $(SIZE)>(\
$for(i in range(0, SIZE))\
\
$# Trailing comma between arguments
$if(i != 0)\
, \
$endif\
\
$if(PARAMETERS == "Vec_Vec")\
a[$(i)] $(OPERATOR) b[$(i)]\
\
$elif(PARAMETERS == "Vec_Scalar")\
a[$(i)] $(OPERATOR) scalar\
\
$else\
scalar $(OPERATOR) a[$(i)]\
\
$endif\
$endfor\
);
}

$endfor\
$endfor\
$endfor\
//}}}
$endfor\


#if defined(VISKORES_MSVC)
#pragma warning(pop)
#endif

#if (defined(VISKORES_CUDA) && (__CUDACC_VER_MAJOR__ < 8))
#if (defined(VISKORES_GCC) || defined(VISKORES_CLANG))
#pragma GCC diagnostic pop
#endif // gcc || clang
#endif // use cuda < 8

}

// clang-format on
#endif //viskores_internal_VecOperators_h
