#include <vtkm/Types.h>

////
//// BEGIN-EXAMPLE TransformArrayFunctor.cxx
////
template<typename T>
struct ScaleBiasFunctor
{
  VTKM_EXEC_CONT
  ScaleBiasFunctor(T scale = T(1), T bias = T(0))
    : Scale(scale)
    , Bias(bias)
  {
  }

  VTKM_EXEC_CONT
  T operator()(T x) const { return this->Scale * x + this->Bias; }

  T Scale;
  T Bias;
};
////
//// END-EXAMPLE TransformArrayFunctor.cxx
////

////
//// BEGIN-EXAMPLE TransformArrayHandle.cxx
////
#include <vtkm/cont/ArrayHandleTransform.h>

template<typename ArrayHandleType>
class ArrayHandleScaleBias
  : public vtkm::cont::ArrayHandleTransform<
      ArrayHandleType,
      ScaleBiasFunctor<typename ArrayHandleType::ValueType>>
{
  VTKM_IS_ARRAY_HANDLE(ArrayHandleType);

public:
  VTKM_ARRAY_HANDLE_SUBCLASS(
    ArrayHandleScaleBias,
    (ArrayHandleScaleBias<ArrayHandleType>),
    (vtkm::cont::ArrayHandleTransform<
      ArrayHandleType,
      ScaleBiasFunctor<typename ArrayHandleType::ValueType>>));

  VTKM_CONT
  ArrayHandleScaleBias(const ArrayHandleType& array, ValueType scale, ValueType bias)
    : Superclass(array, ScaleBiasFunctor<ValueType>(scale, bias))
  {
  }
};

template<typename ArrayHandleType>
VTKM_CONT ArrayHandleScaleBias<ArrayHandleType> make_ArrayHandleScaleBias(
  const ArrayHandleType& array,
  typename ArrayHandleType::ValueType scale,
  typename ArrayHandleType::ValueType bias)
{
  return ArrayHandleScaleBias<ArrayHandleType>(array, scale, bias);
}
////
//// END-EXAMPLE TransformArrayHandle.cxx
////

#include <vtkm/cont/DeviceAdapter.h>

#include <vtkm/cont/testing/Testing.h>

#include <vector>

namespace
{

template<typename ArrayHandleType>
void CheckArray(const ArrayHandleType& array)
{
  for (vtkm::Id index = 0; index < array.GetNumberOfValues(); index++)
  {
    VTKM_TEST_ASSERT(test_equal(array.ReadPortal().Get(index),
                                2 * TestValue(index, vtkm::Float32()) + 3),
                     "Bad transformed value.");
  }
}

void Test()
{
  vtkm::cont::ArrayHandle<vtkm::Float32> array;
  array.Allocate(10);
  SetPortal(array.WritePortal());

  CheckArray(
    ////
    //// BEGIN-EXAMPLE MakeArrayHandleTransform.cxx
    ////
    vtkm::cont::make_ArrayHandleTransform(array,
                                          ScaleBiasFunctor<vtkm::Float32>(2, 3))
    ////
    //// END-EXAMPLE MakeArrayHandleTransform.cxx
    ////
  );

  ArrayHandleScaleBias<vtkm::cont::ArrayHandle<vtkm::Float32>> transformArray(
    array, 2, 3);

  CheckArray(transformArray);

  CheckArray(make_ArrayHandleScaleBias(array, 2, 3));
}

} // anonymous namespace

int ArrayHandleTransform(int argc, char* argv[])
{
  return vtkm::cont::testing::Testing::Run(Test, argc, argv);
}
