Allow for different types in basic type operators

The basic type operators in `Types.h` (i.e. `vtkm::Add`,
`vtkm::Subtract`, `vtkm::Multiply` and `vtkm::Divide`) required the same
type for both arguments. This caused problems when used with `Reduce`
and the initial value type did not match exactly.

Use some tricks from `BinaryOperators.h` to be flexible about using
different types.
This commit is contained in:
Kenneth Moreland 2021-03-02 13:08:51 -07:00
parent 58bd890c9c
commit d9c988b200
2 changed files with 59 additions and 15 deletions

@ -221,37 +221,81 @@ struct NullType
#endif // gcc || clang
struct Add
{
template <typename T>
inline VTKM_EXEC_CONT T operator()(const T& a, const T& b) const
template <typename T, typename U>
inline VTKM_EXEC_CONT auto operator()(const T& a, const U& b) const -> decltype(a + b)
{
return T(a + b);
return a + b;
}
// If both arguments are short integers, explicitly cast the result back to the
// type to avoid narrowing conversion warnings from operations that promote to
// integers.
template <typename T>
inline VTKM_EXEC_CONT
typename std::enable_if<std::is_integral<T>::value && sizeof(T) < sizeof(int), T>::type
operator()(T a, T b) const
{
return static_cast<T>(a + b);
}
};
struct Subtract
{
template <typename T>
inline VTKM_EXEC_CONT T operator()(const T& a, const T& b) const
template <typename T, typename U>
inline VTKM_EXEC_CONT auto operator()(const T& a, const U& b) const -> decltype(a - b)
{
return T(a - b);
return a - b;
}
// If both arguments are short integers, explicitly cast the result back to the
// type to avoid narrowing conversion warnings from operations that promote to
// integers.
template <typename T>
inline VTKM_EXEC_CONT
typename std::enable_if<std::is_integral<T>::value && sizeof(T) < sizeof(int), T>::type
operator()(T a, T b) const
{
return static_cast<T>(a - b);
}
};
struct Multiply
{
template <typename T>
inline VTKM_EXEC_CONT T operator()(const T& a, const T& b) const
template <typename T, typename U>
inline VTKM_EXEC_CONT auto operator()(const T& a, const U& b) const -> decltype(a * b)
{
return T(a * b);
return a * b;
}
// If both arguments are short integers, explicitly cast the result back to the
// type to avoid narrowing conversion warnings from operations that promote to
// integers.
template <typename T>
inline VTKM_EXEC_CONT
typename std::enable_if<std::is_integral<T>::value && sizeof(T) < sizeof(int), T>::type
operator()(T a, T b) const
{
return static_cast<T>(a * b);
}
};
struct Divide
{
template <typename T>
inline VTKM_EXEC_CONT T operator()(const T& a, const T& b) const
template <typename T, typename U>
inline VTKM_EXEC_CONT auto operator()(const T& a, const U& b) const -> decltype(a / b)
{
return T(a / b);
return a / b;
}
// If both arguments are short integers, explicitly cast the result back to the
// type to avoid narrowing conversion warnings from operations that promote to
// integers.
template <typename T>
inline VTKM_EXEC_CONT
typename std::enable_if<std::is_integral<T>::value && sizeof(T) < sizeof(int), T>::type
operator()(T a, T b) const
{
return static_cast<T>(a / b);
}
};

@ -1332,17 +1332,17 @@ private:
//the output of reduce and scan inclusive should be the same
std::cout << " Reduce with initial value of 0." << std::endl;
vtkm::Id reduce_sum = Algorithm::Reduce(array, vtkm::Id(0));
vtkm::Id reduce_sum = Algorithm::Reduce(array, 0);
std::cout << " Reduce with initial value." << std::endl;
vtkm::Id reduce_sum_with_intial_value = Algorithm::Reduce(array, vtkm::Id(ARRAY_SIZE));
std::cout << " Inclusive scan to check" << std::endl;
vtkm::Id inclusive_sum = Algorithm::ScanInclusive(array, array);
std::cout << " Reduce with 1 value." << std::endl;
array.Allocate(1, vtkm::CopyFlag::On);
vtkm::Id reduce_sum_one_value = Algorithm::Reduce(array, vtkm::Id(0));
vtkm::Id reduce_sum_one_value = Algorithm::Reduce(array, 0);
std::cout << " Reduce with 0 values." << std::endl;
array.Allocate(0);
vtkm::Id reduce_sum_no_values = Algorithm::Reduce(array, vtkm::Id(0));
vtkm::Id reduce_sum_no_values = Algorithm::Reduce(array, 0);
VTKM_TEST_ASSERT(reduce_sum == OFFSET * ARRAY_SIZE, "Got bad sum from Reduce");
VTKM_TEST_ASSERT(reduce_sum_with_intial_value == reduce_sum + ARRAY_SIZE,
"Got bad sum from Reduce with initial value");