mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-09-16 17:22:55 +00:00
Check value type in Invoke input arrays.
Instead of just checking that a dispatcher's Invoke input is an ArrayHandle, also check that the ValueType of the ArrayHandle is compatible with the types of the worklet operator. This is done by adding a template argument to the ControlSignature tags that is a type list tag that gets passed to the type check.
This commit is contained in:
parent
f4fb9f0ace
commit
6b1db2cf04
@ -22,6 +22,8 @@
|
||||
|
||||
#include <vtkm/cont/arg/TypeCheck.h>
|
||||
|
||||
#include <vtkm/ListTag.h>
|
||||
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
|
||||
namespace vtkm {
|
||||
@ -31,13 +33,40 @@ namespace arg {
|
||||
/// The Array type check passes for any object that behaves like an \c
|
||||
/// ArrayHandle class and can be passed to the ArrayIn and ArrayOut transports.
|
||||
///
|
||||
struct TypeCheckTagArray { };
|
||||
template<typename TypeList>
|
||||
struct TypeCheckTagArray
|
||||
{
|
||||
VTKM_IS_LIST_TAG(TypeList);
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
struct TypeCheck<TypeCheckTagArray, Type>
|
||||
namespace detail {
|
||||
|
||||
template<typename TypeList, typename ArrayType, bool IsArray>
|
||||
struct TypeCheckArrayValueType;
|
||||
|
||||
template<typename TypeList, typename ArrayType>
|
||||
struct TypeCheckArrayValueType<TypeList, ArrayType, true>
|
||||
{
|
||||
static const bool value =
|
||||
vtkm::cont::internal::ArrayHandleCheck<Type>::type::value;
|
||||
vtkm::ListContains<TypeList,typename ArrayType::ValueType>::value;
|
||||
};
|
||||
|
||||
template<typename TypeList, typename ArrayType>
|
||||
struct TypeCheckArrayValueType<TypeList, ArrayType, false>
|
||||
{
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename TypeList, typename ArrayType>
|
||||
struct TypeCheck<TypeCheckTagArray<TypeList>, ArrayType>
|
||||
{
|
||||
static const bool value =
|
||||
detail::TypeCheckArrayValueType<
|
||||
TypeList,
|
||||
ArrayType,
|
||||
vtkm::cont::internal::ArrayHandleCheck<ArrayType>::type::value>::value;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -34,7 +34,8 @@ struct TryArraysOfType
|
||||
void operator()(T) const
|
||||
{
|
||||
using vtkm::cont::arg::TypeCheck;
|
||||
using vtkm::cont::arg::TypeCheckTagArray;
|
||||
typedef vtkm::cont::arg::TypeCheckTagArray<vtkm::TypeListTagAll>
|
||||
TypeCheckTagArray;
|
||||
|
||||
typedef vtkm::cont::ArrayHandle<T> StandardArray;
|
||||
VTKM_TEST_ASSERT((TypeCheck<TypeCheckTagArray,StandardArray>::value),
|
||||
@ -55,7 +56,6 @@ struct TryArraysOfType
|
||||
"Not an array type check failed.");
|
||||
|
||||
// Another type that is not a valid array.
|
||||
typedef typename StandardArray::PortalControl NotAnArray;
|
||||
VTKM_TEST_ASSERT(!(TypeCheck<TypeCheckTagArray,T>::value),
|
||||
"Not an array type check failed.");
|
||||
}
|
||||
@ -64,6 +64,27 @@ struct TryArraysOfType
|
||||
void TestCheckArray()
|
||||
{
|
||||
vtkm::testing::Testing::TryAllTypes(TryArraysOfType());
|
||||
|
||||
std::cout << "Trying some arrays with types that do not match the list."
|
||||
<< std::endl;
|
||||
using vtkm::cont::arg::TypeCheck;
|
||||
using vtkm::cont::arg::TypeCheckTagArray;
|
||||
|
||||
typedef vtkm::cont::ArrayHandle<vtkm::FloatDefault> ScalarArray;
|
||||
VTKM_TEST_ASSERT(
|
||||
(TypeCheck<TypeCheckTagArray<vtkm::TypeListTagFieldScalar>,ScalarArray>::value),
|
||||
"Scalar for scalar check failed.");
|
||||
VTKM_TEST_ASSERT(
|
||||
!(TypeCheck<TypeCheckTagArray<vtkm::TypeListTagFieldVec3>,ScalarArray>::value),
|
||||
"Scalar for vector check failed.");
|
||||
|
||||
typedef vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::FloatDefault,3> > VecArray;
|
||||
VTKM_TEST_ASSERT(
|
||||
(TypeCheck<TypeCheckTagArray<vtkm::TypeListTagFieldVec3>,VecArray>::value),
|
||||
"Vector for vector check failed.");
|
||||
VTKM_TEST_ASSERT(
|
||||
!(TypeCheck<TypeCheckTagArray<vtkm::TypeListTagFieldScalar>,VecArray>::value),
|
||||
"Vector for scalar check failed.");
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
@ -22,6 +22,8 @@
|
||||
|
||||
#include <vtkm/worklet/internal/WorkletBase.h>
|
||||
|
||||
#include <vtkm/TypeListTag.h>
|
||||
|
||||
#include <vtkm/cont/arg/TransportTagArrayIn.h>
|
||||
#include <vtkm/cont/arg/TransportTagArrayOut.h>
|
||||
#include <vtkm/cont/arg/TypeCheckTagArray.h>
|
||||
@ -39,16 +41,26 @@ namespace worklet {
|
||||
class WorkletMapField : public vtkm::worklet::internal::WorkletBase
|
||||
{
|
||||
public:
|
||||
/// A control signature tag for input fields.
|
||||
/// \brief A control signature tag for input fields.
|
||||
///
|
||||
/// This tag takes a template argument that is a type list tag that limits
|
||||
/// the possible value types in the array.
|
||||
///
|
||||
template<typename TypeList = AllTypes>
|
||||
struct FieldIn {
|
||||
typedef vtkm::cont::arg::TypeCheckTagArray TypeCheckTag;
|
||||
typedef vtkm::cont::arg::TypeCheckTagArray<TypeList> TypeCheckTag;
|
||||
typedef vtkm::cont::arg::TransportTagArrayIn TransportTag;
|
||||
typedef vtkm::exec::arg::FetchTagArrayDirectIn FetchTag;
|
||||
};
|
||||
|
||||
/// A control signature tag for output fields.
|
||||
/// \brief A control signature tag for output fields.
|
||||
///
|
||||
/// This tag takes a template argument that is a type list tag that limits
|
||||
/// the possible value types in the array.
|
||||
///
|
||||
template<typename TypeList = AllTypes>
|
||||
struct FieldOut {
|
||||
typedef vtkm::cont::arg::TypeCheckTagArray TypeCheckTag;
|
||||
typedef vtkm::cont::arg::TypeCheckTagArray<TypeList> TypeCheckTag;
|
||||
typedef vtkm::cont::arg::TransportTagArrayOut TransportTag;
|
||||
typedef vtkm::exec::arg::FetchTagArrayDirectOut FetchTag;
|
||||
};
|
||||
|
@ -20,6 +20,8 @@
|
||||
#ifndef vtk_m_worklet_internal_WorkletBase_h
|
||||
#define vtk_m_worklet_internal_WorkletBase_h
|
||||
|
||||
#include <vtkm/TypeListTag.h>
|
||||
|
||||
#include <vtkm/exec/FunctorBase.h>
|
||||
#include <vtkm/exec/arg/BasicArg.h>
|
||||
#include <vtkm/exec/arg/FetchTagExecObject.h>
|
||||
@ -66,6 +68,90 @@ public:
|
||||
/// Default input domain is the first argument. Worklet subclasses can
|
||||
/// override this by redefining this type.
|
||||
typedef _1 InputDomain;
|
||||
|
||||
/// \brief A type list containing the type vtkm::Id.
|
||||
///
|
||||
/// This is a convenience type to use as template arguments to \c
|
||||
/// ControlSignature tags to specify the types of worklet arguments.
|
||||
typedef vtkm::TypeListTagId IdType;
|
||||
|
||||
/// \brief A type list containing the type vtkm::Id2.
|
||||
///
|
||||
/// This is a convenience type to use as template arguments to \c
|
||||
/// ControlSignature tags to specify the types of worklet arguments.
|
||||
typedef vtkm::TypeListTagId2 Id2Type;
|
||||
|
||||
/// \brief A type list containing the type vtkm::Id3.
|
||||
///
|
||||
/// This is a convenience type to use as template arguments to \c
|
||||
/// ControlSignature tags to specify the types of worklet arguments.
|
||||
typedef vtkm::TypeListTagId3 Id3Type;
|
||||
|
||||
/// \brief A list of types commonly used for indexing.
|
||||
///
|
||||
/// This is a convenience type to use as template arguments to \c
|
||||
/// ControlSignature tags to specify the types of worklet arguments.
|
||||
typedef vtkm::TypeListTagIndex Index;
|
||||
|
||||
/// \brief A list of types commonly used for scalar fields.
|
||||
///
|
||||
/// This is a convenience type to use as template arguments to \c
|
||||
/// ControlSignature tags to specify the types of worklet arguments.
|
||||
typedef vtkm::TypeListTagFieldScalar Scalar;
|
||||
|
||||
/// \brief A list of all basic types used for scalar fields.
|
||||
///
|
||||
/// This is a convenience type to use as template arguments to \c
|
||||
/// ControlSignature tags to specify the types of worklet arguments.
|
||||
typedef vtkm::TypeListTagScalarAll ScalarAll;
|
||||
|
||||
/// \brief A list of types commonly used for vector fields of 2 components.
|
||||
///
|
||||
/// This is a convenience type to use as template arguments to \c
|
||||
/// ControlSignature tags to specify the types of worklet arguments.
|
||||
typedef vtkm::TypeListTagFieldVec2 Vec2;
|
||||
|
||||
/// \brief A list of types commonly used for vector fields of 3 components.
|
||||
///
|
||||
/// This is a convenience type to use as template arguments to \c
|
||||
/// ControlSignature tags to specify the types of worklet arguments.
|
||||
typedef vtkm::TypeListTagFieldVec3 Vec3;
|
||||
|
||||
/// \brief A list of types commonly used for vector fields of 4 components.
|
||||
///
|
||||
/// This is a convenience type to use as template arguments to \c
|
||||
/// ControlSignature tags to specify the types of worklet arguments.
|
||||
typedef vtkm::TypeListTagFieldVec4 Vec4;
|
||||
|
||||
/// \brief A list of all basic types used for vector fields.
|
||||
///
|
||||
/// This is a convenience type to use as template arguments to \c
|
||||
/// ControlSignature tags to specify the types of worklet arguments.
|
||||
typedef vtkm::TypeListTagVecAll VecAll;
|
||||
|
||||
/// \brief A list of types (scalar and vector) commonly used in fields.
|
||||
///
|
||||
/// This is a convenience type to use as template arguments to \c
|
||||
/// ControlSignature tags to specify the types of worklet arguments.
|
||||
typedef vtkm::TypeListTagField FieldCommon;
|
||||
|
||||
/// \brief A list of vector types commonly used in fields.
|
||||
///
|
||||
/// This is a convenience type to use as template arguments to \c
|
||||
/// ControlSignature tags to specify the types of worklet arguments.
|
||||
typedef vtkm::TypeListTagVecCommon VecCommon;
|
||||
|
||||
/// \brief A list of generally common types.
|
||||
///
|
||||
/// This is a convenience type to use as template arguments to \c
|
||||
/// ControlSignature tags to specify the types of worklet arguments.
|
||||
typedef vtkm::TypeListTagCommon CommonTypes;
|
||||
|
||||
/// \brief A list of all basic types.
|
||||
///
|
||||
/// This is a convenience type to use as template arguments to \c
|
||||
/// ControlSignature tags to specify the types of worklet arguments.
|
||||
typedef vtkm::TypeListTagAll AllTypes;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -33,20 +33,44 @@ static const vtkm::Id ARRAY_SIZE = 10;
|
||||
class TestWorklet : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
public:
|
||||
typedef void ControlSignature(FieldIn, FieldOut);
|
||||
typedef _2 ExecutionSignature(_1, WorkIndex);
|
||||
typedef void ControlSignature(FieldIn<>, FieldOut<>);
|
||||
typedef void ExecutionSignature(_1, _2, WorkIndex);
|
||||
|
||||
template<typename T>
|
||||
T operator()(T x, vtkm::Id workIndex) const
|
||||
void operator()(const T &in, T &out, vtkm::Id workIndex) const
|
||||
{
|
||||
if (x != TestValue(workIndex, T()) + T(100))
|
||||
if (in != TestValue(workIndex, T()) + T(100))
|
||||
{
|
||||
this->RaiseError("Got wrong input value.");
|
||||
}
|
||||
return x - T(100);
|
||||
out = in - T(100);
|
||||
}
|
||||
|
||||
template<typename T1, typename T2>
|
||||
void operator()(const T1 &, const T2 &, vtkm::Id) const
|
||||
{
|
||||
this->RaiseError("Cannot call this worklet with different types.");
|
||||
}
|
||||
};
|
||||
|
||||
class TestWorkletLimitedTypes : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
public:
|
||||
typedef void ControlSignature(FieldIn<ScalarAll>, FieldOut<ScalarAll>);
|
||||
typedef _2 ExecutionSignature(_1, WorkIndex);
|
||||
|
||||
template<typename T>
|
||||
T operator()(const T &in, vtkm::Id workIndex) const
|
||||
{
|
||||
if (in != TestValue(workIndex, T()) + T(100))
|
||||
{
|
||||
this->RaiseError("Got wrong input value.");
|
||||
}
|
||||
return in - T(100);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename WorkletType>
|
||||
struct DoTestWorklet
|
||||
{
|
||||
template<typename T>
|
||||
@ -66,51 +90,42 @@ struct DoTestWorklet
|
||||
vtkm::cont::ArrayHandle<T> outputHandle;
|
||||
|
||||
std::cout << "Create and run dispatcher." << std::endl;
|
||||
vtkm::worklet::DispatcherMapField<TestWorklet> dispatcher;
|
||||
vtkm::worklet::DispatcherMapField<WorkletType> dispatcher;
|
||||
dispatcher.Invoke(inputHandle, outputHandle);
|
||||
|
||||
std::cout << "Check result." << std::endl;
|
||||
CheckPortal(outputHandle.GetPortalConstControl());
|
||||
|
||||
// The following test is commented out because as of this writing
|
||||
// (10-21-2014) there is an issue with getting unexpected types when
|
||||
// casting dynamic arrays. In particular, this issue is with using dynamic
|
||||
// arrays. We know that both arrays will always be the same type, but the
|
||||
// arrays are cast independently. Thus, the compiler will generate code for
|
||||
// odd combinations that are incompatibile with each other. Thus, we need a
|
||||
// way to better specify the types expected by the worklet function. I can
|
||||
// think of two general ways (there might be more).
|
||||
//
|
||||
// 1. Specify the expected type in the ControlSignature. This would
|
||||
// probably be a template argument of the tag with a list of basic types
|
||||
// that could be in the array. The dynamic array casting would then take
|
||||
// that into account and only try those specified types. That should be
|
||||
// fairly straightforward to implement and handle many cases. However, it
|
||||
// still has the problem that all dynamic arrays are cast independently.
|
||||
// Thus, for example, if you have a worklet that can operate on vectors of
|
||||
// any size, you will likely get a compile error when trying to operate on
|
||||
// two vectors of different size when you expected them to be the same.
|
||||
// This particular general case might actually be quite rare, so in that
|
||||
// case the user has the onus to create a default template that handles
|
||||
// this exceptional case with failure.
|
||||
//
|
||||
// 2. Have a mechanism to identify when the type of two things is expected
|
||||
// to be the same. I'm not sure what the programming interface for that
|
||||
// would look though.
|
||||
//
|
||||
// std::cout << "Repeat with dynamic arrays." << std::endl;
|
||||
// // Clear out output array.
|
||||
// outputHandle = vtkm::cont::ArrayHandle<T>();
|
||||
// vtkm::cont::DynamicArrayHandle inputDynamic(inputHandle);
|
||||
// vtkm::cont::DynamicArrayHandle outputDynamic(outputHandle);
|
||||
// dispatcher.Invoke(inputDynamic, outputDynamic);
|
||||
// CheckPortal(outputHandle.GetPortalConstControl());
|
||||
std::cout << "Repeat with dynamic arrays." << std::endl;
|
||||
// Clear out output array.
|
||||
outputHandle = vtkm::cont::ArrayHandle<T>();
|
||||
vtkm::cont::DynamicArrayHandle inputDynamic(inputHandle);
|
||||
vtkm::cont::DynamicArrayHandle outputDynamic(outputHandle);
|
||||
dispatcher.Invoke(inputDynamic, outputDynamic);
|
||||
CheckPortal(outputHandle.GetPortalConstControl());
|
||||
}
|
||||
};
|
||||
|
||||
void TestWorkletMapField()
|
||||
{
|
||||
vtkm::testing::Testing::TryTypes(DoTestWorklet(), vtkm::TypeListTagCommon());
|
||||
std::cout << "--- Worklet accepting all types." << std::endl;
|
||||
vtkm::testing::Testing::TryTypes(DoTestWorklet<TestWorklet>(),
|
||||
vtkm::TypeListTagCommon());
|
||||
|
||||
std::cout << "--- Worklet accepting some types." << std::endl;
|
||||
vtkm::testing::Testing::TryTypes(DoTestWorklet<TestWorkletLimitedTypes>(),
|
||||
vtkm::TypeListTagFieldScalar());
|
||||
|
||||
std::cout << "--- Sending bad type to worklet." << std::endl;
|
||||
try
|
||||
{
|
||||
DoTestWorklet<TestWorkletLimitedTypes>()(vtkm::Vec<vtkm::Float32,3>());
|
||||
VTKM_TEST_FAIL("Did not throw expected error.");
|
||||
}
|
||||
catch (vtkm::cont::ErrorControlBadType &error)
|
||||
{
|
||||
std::cout << "Got expected error: " << error.GetMessage() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
Loading…
Reference in New Issue
Block a user