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:
Robert Maynard 2015-10-27 08:49:49 -04:00 committed by Kitware Robot
commit adace4e10e
3 changed files with 200 additions and 28 deletions

@ -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 &parameters) const { void operator()(const FunctionInterface &parameters) 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> &parameters,
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> &parameters,
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> &parameters) const const vtkm::internal::FunctionInterface<Signature> &parameters,
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.");
} }