mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-09-19 18:45:43 +00:00
Merge topic 'conditionaly_check_for_dynamic_types_in_dispatcher'
ca71d70b Update worklet UnitTests to not try statically known invalid combinations 6b2edb70 Update UnitTestDispatcherBase to use verify DynamicTransform error messages. 9fdc0f09 Improve the error message for Invoke type mismatch at compile time. 54d25fae Only perform DynamicTransformCont if at least one parameter is dynamic. Acked-by: Kitware Robot <kwrobot@kitware.com> Merge-request: !249
This commit is contained in:
commit
adace4e10e
@ -39,7 +39,12 @@
|
|||||||
#include <vtkm/exec/internal/WorkletInvokeFunctor.h>
|
#include <vtkm/exec/internal/WorkletInvokeFunctor.h>
|
||||||
|
|
||||||
VTKM_THIRDPARTY_PRE_INCLUDE
|
VTKM_THIRDPARTY_PRE_INCLUDE
|
||||||
|
#include <boost/mpl/at.hpp>
|
||||||
#include <boost/mpl/assert.hpp>
|
#include <boost/mpl/assert.hpp>
|
||||||
|
#include <boost/mpl/fold.hpp>
|
||||||
|
#include <boost/mpl/find.hpp>
|
||||||
|
#include <boost/mpl/zip_view.hpp>
|
||||||
|
#include <boost/mpl/vector.hpp>
|
||||||
#include <boost/type_traits/is_base_of.hpp>
|
#include <boost/type_traits/is_base_of.hpp>
|
||||||
#include <boost/utility/enable_if.hpp>
|
#include <boost/utility/enable_if.hpp>
|
||||||
VTKM_THIRDPARTY_POST_INCLUDE
|
VTKM_THIRDPARTY_POST_INCLUDE
|
||||||
@ -70,6 +75,65 @@ inline void PrintFailureMessage(int index, boost::false_type)
|
|||||||
throw vtkm::cont::ErrorControlBadType(message.str());
|
throw vtkm::cont::ErrorControlBadType(message.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Is designed as a boost mpl binary metafunction.
|
||||||
|
struct DetermineIfHasDynamicParameter
|
||||||
|
{
|
||||||
|
template<typename T, typename U>
|
||||||
|
struct apply
|
||||||
|
{
|
||||||
|
typedef typename vtkm::cont::internal::DynamicTransformTraits<U>::DynamicTag DynamicTag;
|
||||||
|
typedef typename boost::is_same<
|
||||||
|
DynamicTag,
|
||||||
|
vtkm::cont::internal::DynamicTransformTagCastAndCall>::type UType;
|
||||||
|
|
||||||
|
typedef typename boost::mpl::or_<T,UType>::type type;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename ValueType, typename TagList>
|
||||||
|
void NiceInCorrectParameterErrorMessage()
|
||||||
|
{
|
||||||
|
VTKM_STATIC_ASSERT_MSG(ValueType() == TagList(),
|
||||||
|
"Unable to match 'ValueType' to the signature tag 'ControlSignatureTag'" );
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void ShowInCorrectParameter(boost::mpl::true_, T) {}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void ShowInCorrectParameter(boost::mpl::false_, T)
|
||||||
|
{
|
||||||
|
typedef typename boost::mpl::deref<T>::type ZipType;
|
||||||
|
typedef typename boost::mpl::at_c<ZipType,0>::type ValueType;
|
||||||
|
typedef typename boost::mpl::at_c<ZipType,1>::type ControlSignatureTag;
|
||||||
|
NiceInCorrectParameterErrorMessage<ValueType,ControlSignatureTag>();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Is designed as a boost mpl unary metafunction.
|
||||||
|
struct DetermineHasInCorrectParameters
|
||||||
|
{
|
||||||
|
//When we find parameters that don't match, we set our 'type' to true_
|
||||||
|
//otherwise we are false_
|
||||||
|
template<typename T>
|
||||||
|
struct apply
|
||||||
|
{
|
||||||
|
typedef typename boost::mpl::at_c<T,0>::type ValueType;
|
||||||
|
typedef typename boost::mpl::at_c<T,1>::type ControlSignatureTag;
|
||||||
|
|
||||||
|
typedef typename ControlSignatureTag::TypeCheckTag TypeCheckTag;
|
||||||
|
|
||||||
|
typedef boost::mpl::bool_<
|
||||||
|
vtkm::cont::arg::TypeCheck<TypeCheckTag,ValueType>::value> CanContinueTagType;
|
||||||
|
|
||||||
|
//We need to not the result of CanContinueTagType, because we want to return
|
||||||
|
//true when we have the first parameter that DOES NOT match the control
|
||||||
|
//signature requirements
|
||||||
|
typedef typename boost::mpl::not_< typename CanContinueTagType::type
|
||||||
|
>::type type;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
// Checks that an argument in a ControlSignature is a valid control signature
|
// Checks that an argument in a ControlSignature is a valid control signature
|
||||||
// tag. Causes a compile error otherwise.
|
// tag. Causes a compile error otherwise.
|
||||||
struct DispatcherBaseControlSignatureTagCheck
|
struct DispatcherBaseControlSignatureTagCheck
|
||||||
@ -175,7 +239,7 @@ struct DispatcherBaseDynamicTransformHelper
|
|||||||
template<typename FunctionInterface>
|
template<typename FunctionInterface>
|
||||||
VTKM_CONT_EXPORT
|
VTKM_CONT_EXPORT
|
||||||
void operator()(const FunctionInterface ¶meters) const {
|
void operator()(const FunctionInterface ¶meters) const {
|
||||||
this->Dispatcher->DynamicTransformInvoke(parameters);
|
this->Dispatcher->DynamicTransformInvoke(parameters, boost::mpl::true_() );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -275,6 +339,28 @@ private:
|
|||||||
|
|
||||||
BOOST_MPL_ASSERT(( boost::is_base_of<BaseWorkletType,WorkletType> ));
|
BOOST_MPL_ASSERT(( boost::is_base_of<BaseWorkletType,WorkletType> ));
|
||||||
|
|
||||||
|
//We need to determine if we have the need to do any dynamic
|
||||||
|
//transforms. This is fairly simple of a query. We just need to check
|
||||||
|
//everything in the FunctionInterface and see if any of them have the
|
||||||
|
//proper dynamic trait. Doing this, allows us to generate zero dynamic
|
||||||
|
//check & convert code when we already know all the types. This results
|
||||||
|
//in smaller executables and libraries.
|
||||||
|
typedef boost::function_types::parameter_types<Signature> MPLSignatureForm;
|
||||||
|
typedef typename boost::mpl::fold<
|
||||||
|
MPLSignatureForm,
|
||||||
|
boost::mpl::false_,
|
||||||
|
detail::DetermineIfHasDynamicParameter>::type HasDynamicTypes;
|
||||||
|
|
||||||
|
this->StartInvokeDynamic(parameters, HasDynamicTypes() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Signature>
|
||||||
|
VTKM_CONT_EXPORT
|
||||||
|
void StartInvokeDynamic(
|
||||||
|
const vtkm::internal::FunctionInterface<Signature> ¶meters,
|
||||||
|
boost::mpl::true_) const
|
||||||
|
{
|
||||||
// As we do the dynamic transform, we are also going to check the static
|
// As we do the dynamic transform, we are also going to check the static
|
||||||
// type against the TypeCheckTag in the ControlSignature tags. To do this,
|
// type against the TypeCheckTag in the ControlSignature tags. To do this,
|
||||||
// the check needs access to both the parameter (in the parameters
|
// the check needs access to both the parameter (in the parameters
|
||||||
@ -289,10 +375,43 @@ private:
|
|||||||
detail::DispatcherBaseDynamicTransformHelper<MyType>(this));
|
detail::DispatcherBaseDynamicTransformHelper<MyType>(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Signature>
|
||||||
|
VTKM_CONT_EXPORT
|
||||||
|
void StartInvokeDynamic(
|
||||||
|
const vtkm::internal::FunctionInterface<Signature> ¶meters,
|
||||||
|
boost::mpl::false_) const
|
||||||
|
{
|
||||||
|
//Nothing requires a conversion from dynamic to static types, so
|
||||||
|
//next we need to verify that each argument's type is correct. If not
|
||||||
|
//we need to throw a nice compile time error
|
||||||
|
typedef boost::function_types::parameter_types<Signature> MPLSignatureForm;
|
||||||
|
typedef typename boost::function_types::parameter_types<
|
||||||
|
typename WorkletType::ControlSignature > WorkletContSignature;
|
||||||
|
|
||||||
|
typedef boost::mpl::vector< MPLSignatureForm, WorkletContSignature > ZippedSignatures;
|
||||||
|
typedef boost::mpl::zip_view<ZippedSignatures> ZippedView;
|
||||||
|
|
||||||
|
typedef typename boost::mpl::find_if<
|
||||||
|
ZippedView,
|
||||||
|
detail::DetermineHasInCorrectParameters>::type LocationOfIncorrectParameter;
|
||||||
|
|
||||||
|
typedef typename boost::is_same< LocationOfIncorrectParameter,
|
||||||
|
typename boost::mpl::end< ZippedView>::type >::type HasOnlyCorrectTypes;
|
||||||
|
|
||||||
|
//When HasOnlyCorrectTypes is false we produce an error
|
||||||
|
//message which should state what the parameter type and tag type is
|
||||||
|
//that failed to match.
|
||||||
|
detail::ShowInCorrectParameter(HasOnlyCorrectTypes(),
|
||||||
|
LocationOfIncorrectParameter());
|
||||||
|
|
||||||
|
this->DynamicTransformInvoke(parameters, HasOnlyCorrectTypes());
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Signature>
|
template<typename Signature>
|
||||||
VTKM_CONT_EXPORT
|
VTKM_CONT_EXPORT
|
||||||
void DynamicTransformInvoke(
|
void DynamicTransformInvoke(
|
||||||
const vtkm::internal::FunctionInterface<Signature> ¶meters) const
|
const vtkm::internal::FunctionInterface<Signature> ¶meters,
|
||||||
|
boost::mpl::true_ ) const
|
||||||
{
|
{
|
||||||
// TODO: Check parameters
|
// TODO: Check parameters
|
||||||
static const vtkm::IdComponent INPUT_DOMAIN_INDEX =
|
static const vtkm::IdComponent INPUT_DOMAIN_INDEX =
|
||||||
@ -302,6 +421,14 @@ private:
|
|||||||
parameters, ControlInterface(), ExecutionInterface()));
|
parameters, ControlInterface(), ExecutionInterface()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Signature>
|
||||||
|
VTKM_CONT_EXPORT
|
||||||
|
void DynamicTransformInvoke(
|
||||||
|
const vtkm::internal::FunctionInterface<Signature> &,
|
||||||
|
boost::mpl::false_ ) const
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Implementation of the Invoke method is in this generated file.
|
// Implementation of the Invoke method is in this generated file.
|
||||||
#include <vtkm/worklet/internal/DispatcherBaseDetailInvoke.h>
|
#include <vtkm/worklet/internal/DispatcherBaseDetailInvoke.h>
|
||||||
|
@ -45,6 +45,16 @@ struct TestExecObject
|
|||||||
vtkm::Id *Array;
|
vtkm::Id *Array;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TestExecObjectType : vtkm::exec::ExecutionObjectBase
|
||||||
|
{
|
||||||
|
template<typename Functor>
|
||||||
|
void CastAndCall(Functor f) const
|
||||||
|
{
|
||||||
|
f(*this);
|
||||||
|
}
|
||||||
|
vtkm::Id Value;
|
||||||
|
};
|
||||||
|
|
||||||
struct TestTypeCheckTag { };
|
struct TestTypeCheckTag { };
|
||||||
struct TestTransportTag { };
|
struct TestTransportTag { };
|
||||||
struct TestFetchTagInput { };
|
struct TestFetchTagInput { };
|
||||||
@ -80,6 +90,20 @@ struct Transport<TestTransportTag, vtkm::Id *, Device>
|
|||||||
}
|
}
|
||||||
} // namespace vtkm::cont::arg
|
} // namespace vtkm::cont::arg
|
||||||
|
|
||||||
|
namespace vtkm {
|
||||||
|
namespace cont {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct DynamicTransformTraits< TestExecObjectType >
|
||||||
|
{
|
||||||
|
typedef vtkm::cont::internal::DynamicTransformTagCastAndCall DynamicTag;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace vtkm::cont::internal
|
||||||
|
|
||||||
namespace vtkm {
|
namespace vtkm {
|
||||||
namespace exec {
|
namespace exec {
|
||||||
namespace arg {
|
namespace arg {
|
||||||
@ -135,11 +159,6 @@ struct Fetch<TestFetchTagOutput,
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct TestExecObjectType : vtkm::exec::ExecutionObjectBase
|
|
||||||
{
|
|
||||||
vtkm::Id Value;
|
|
||||||
};
|
|
||||||
|
|
||||||
static const vtkm::Id EXPECTED_EXEC_OBJECT_VALUE = 123;
|
static const vtkm::Id EXPECTED_EXEC_OBJECT_VALUE = 123;
|
||||||
|
|
||||||
class TestWorkletBase : public vtkm::worklet::internal::WorkletBase
|
class TestWorkletBase : public vtkm::worklet::internal::WorkletBase
|
||||||
@ -252,6 +271,7 @@ void TestBasicInvoke()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void TestInvokeWithError()
|
void TestInvokeWithError()
|
||||||
{
|
{
|
||||||
std::cout << "Test invoke with error raised" << std::endl;
|
std::cout << "Test invoke with error raised" << std::endl;
|
||||||
@ -282,7 +302,8 @@ void TestInvokeWithError()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestInvokeWithBadType()
|
|
||||||
|
void TestInvokeWithDynamicAndBadTypes()
|
||||||
{
|
{
|
||||||
std::cout << "Test invoke with bad type" << std::endl;
|
std::cout << "Test invoke with bad type" << std::endl;
|
||||||
|
|
||||||
@ -305,20 +326,6 @@ void TestInvokeWithBadType()
|
|||||||
"Parameter index not named in error message.");
|
"Parameter index not named in error message.");
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
std::cout << " Second argument bad." << std::endl;
|
|
||||||
dispatcher.Invoke(array, NULL, array);
|
|
||||||
VTKM_TEST_FAIL("Dispatcher did not throw expected error.");
|
|
||||||
}
|
|
||||||
catch (vtkm::cont::ErrorControlBadType error)
|
|
||||||
{
|
|
||||||
std::cout << " Got expected exception." << std::endl;
|
|
||||||
std::cout << " " << error.GetMessage() << std::endl;
|
|
||||||
VTKM_TEST_ASSERT(error.GetMessage().find(" 2 ") != std::string::npos,
|
|
||||||
"Parameter index not named in error message.");
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
std::cout << " Third argument bad." << std::endl;
|
std::cout << " Third argument bad." << std::endl;
|
||||||
@ -338,7 +345,7 @@ void TestDispatcherBase()
|
|||||||
{
|
{
|
||||||
TestBasicInvoke();
|
TestBasicInvoke();
|
||||||
TestInvokeWithError();
|
TestInvokeWithError();
|
||||||
TestInvokeWithBadType();
|
TestInvokeWithDynamicAndBadTypes();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
@ -87,7 +87,7 @@ namespace mapfield {
|
|||||||
static const vtkm::Id ARRAY_SIZE = 10;
|
static const vtkm::Id ARRAY_SIZE = 10;
|
||||||
|
|
||||||
template<typename WorkletType>
|
template<typename WorkletType>
|
||||||
struct DoTestWorklet
|
struct DoStaticTestWorklet
|
||||||
{
|
{
|
||||||
template<typename T>
|
template<typename T>
|
||||||
VTKM_CONT_EXPORT
|
VTKM_CONT_EXPORT
|
||||||
@ -116,21 +116,58 @@ struct DoTestWorklet
|
|||||||
std::cout << "Check result." << std::endl;
|
std::cout << "Check result." << std::endl;
|
||||||
CheckPortal(outputHandle.GetPortalConstControl());
|
CheckPortal(outputHandle.GetPortalConstControl());
|
||||||
CheckPortal(inoutHandle.GetPortalConstControl());
|
CheckPortal(inoutHandle.GetPortalConstControl());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename WorkletType>
|
||||||
|
struct DoDynamicTestWorklet
|
||||||
|
{
|
||||||
|
template<typename T>
|
||||||
|
VTKM_CONT_EXPORT
|
||||||
|
void operator()(T) const
|
||||||
|
{
|
||||||
|
std::cout << "Set up data." << std::endl;
|
||||||
|
T inputArray[ARRAY_SIZE];
|
||||||
|
|
||||||
|
for (vtkm::Id index = 0; index < ARRAY_SIZE; index++)
|
||||||
|
{
|
||||||
|
inputArray[index] = TestValue(index, T()) + T(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
vtkm::cont::ArrayHandle<T> inputHandle =
|
||||||
|
vtkm::cont::make_ArrayHandle(inputArray, ARRAY_SIZE);
|
||||||
|
vtkm::cont::ArrayHandle<T> outputHandle;
|
||||||
|
vtkm::cont::ArrayHandle<T> inoutHandle;
|
||||||
|
|
||||||
std::cout << "Repeat with dynamic arrays." << std::endl;
|
|
||||||
// Clear out output array.
|
|
||||||
outputHandle = vtkm::cont::ArrayHandle<T>();
|
|
||||||
vtkm::cont::DeviceAdapterAlgorithm<VTKM_DEFAULT_DEVICE_ADAPTER_TAG>::
|
vtkm::cont::DeviceAdapterAlgorithm<VTKM_DEFAULT_DEVICE_ADAPTER_TAG>::
|
||||||
Copy(inputHandle, inoutHandle);
|
Copy(inputHandle, inoutHandle);
|
||||||
|
|
||||||
|
std::cout << "Create and run dispatcher with dynamic arrays." << std::endl;
|
||||||
|
vtkm::worklet::DispatcherMapField<WorkletType> dispatcher;
|
||||||
|
|
||||||
vtkm::cont::DynamicArrayHandle inputDynamic(inputHandle);
|
vtkm::cont::DynamicArrayHandle inputDynamic(inputHandle);
|
||||||
vtkm::cont::DynamicArrayHandle outputDynamic(outputHandle);
|
vtkm::cont::DynamicArrayHandle outputDynamic(outputHandle);
|
||||||
vtkm::cont::DynamicArrayHandle inoutDynamic(inoutHandle);
|
vtkm::cont::DynamicArrayHandle inoutDynamic(inoutHandle);
|
||||||
|
|
||||||
dispatcher.Invoke(inputDynamic, outputDynamic, inoutDynamic);
|
dispatcher.Invoke(inputDynamic, outputDynamic, inoutDynamic);
|
||||||
|
|
||||||
CheckPortal(outputHandle.GetPortalConstControl());
|
CheckPortal(outputHandle.GetPortalConstControl());
|
||||||
CheckPortal(inoutHandle.GetPortalConstControl());
|
CheckPortal(inoutHandle.GetPortalConstControl());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename WorkletType>
|
||||||
|
struct DoTestWorklet
|
||||||
|
{
|
||||||
|
template<typename T>
|
||||||
|
VTKM_CONT_EXPORT
|
||||||
|
void operator()(T t) const
|
||||||
|
{
|
||||||
|
DoStaticTestWorklet<WorkletType> sw; sw(t);
|
||||||
|
DoDynamicTestWorklet<WorkletType> dw; dw(t);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void TestWorkletMapField()
|
void TestWorkletMapField()
|
||||||
{
|
{
|
||||||
typedef vtkm::cont::internal::DeviceAdapterTraits<
|
typedef vtkm::cont::internal::DeviceAdapterTraits<
|
||||||
@ -151,7 +188,8 @@ void TestWorkletMapField()
|
|||||||
std::cout << "--- Sending bad type to worklet." << std::endl;
|
std::cout << "--- Sending bad type to worklet." << std::endl;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
DoTestWorklet< TestMapFieldWorkletLimitedTypes > badWorkletTest;
|
//can only test with dynamic arrays, as static arrays will fail to compile
|
||||||
|
DoDynamicTestWorklet< TestMapFieldWorkletLimitedTypes > badWorkletTest;
|
||||||
badWorkletTest( vtkm::Vec<vtkm::Float32,3>() );
|
badWorkletTest( vtkm::Vec<vtkm::Float32,3>() );
|
||||||
VTKM_TEST_FAIL("Did not throw expected error.");
|
VTKM_TEST_FAIL("Did not throw expected error.");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user