Add basic support for type checking of Invoke arguments

This commit is contained in:
Kenneth Moreland 2014-10-22 15:15:14 -06:00
parent 9ac538b6b9
commit 421746d041
14 changed files with 484 additions and 31 deletions

@ -35,6 +35,7 @@ set(headers
Error.h
ErrorControl.h
ErrorControlAssert.h
ErrorControlBadType.h
ErrorControlBadValue.h
ErrorControlInternal.h
ErrorControlOutOfMemory.h

@ -0,0 +1,41 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014. Los Alamos National Security
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_cont_ErrorControlBadType_h
#define vtk_m_cont_ErrorControlBadType_h
#include <vtkm/cont/ErrorControl.h>
namespace vtkm {
namespace cont {
/// This class is thrown when VTK-m encounters data of a type that is
/// incompatible with the current operation.
///
class ErrorControlBadType : public ErrorControl
{
public:
ErrorControlBadType(const std::string &message)
: ErrorControl(message) { }
};
}
} // namespace vtkm::cont
#endif //vtk_m_cont_ErrorControlBadType_h

@ -25,6 +25,9 @@ set(headers
TransportTagArrayIn.h
TransportTagArrayOut.h
TransportTagExecObject.h
TypeCheck.h
TypeCheckTagArray.h
TypeCheckTagExecObject.h
)
vtkm_declare_headers(${headers})

53
vtkm/cont/arg/TypeCheck.h Normal file

@ -0,0 +1,53 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014. Los Alamos National Security
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_cont_arg_TypeCheck_h
#define vtk_m_cont_arg_TypeCheck_h
namespace vtkm {
namespace cont {
namespace arg {
/// \brief Class for checking that a type matches the semantics for an argument.
///
/// The \c TypeCheck class is used in dispatchers to test whether an argument
/// passed to the \c Invoke command matches the corresponding argument in the
/// \c ControlSignature.
///
/// This check happens after casting dynamic classes to static classes, so the
/// check need not worry about querying dynamic types.
///
/// The generic implementation of \c TypeCheck always results in failure. When
/// a new type check tag is defined, along with it should be partial
/// specializations that find valid types.
///
template<typename TypeCheckTag, typename Type>
struct TypeCheck
{
/// The static constant boolean \c value is set to \c true if the type is
/// valid for the given check tag and \c false otherwise.
///
static const bool value = false;
};
}
}
} // namespace vtkm::cont::arg
#endif //vtk_m_cont_arg_TypeCheck_h

@ -0,0 +1,47 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014. Los Alamos National Security
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_cont_arg_TypeCheckTagArray_h
#define vtk_m_cont_arg_TypeCheckTagArray_h
#include <vtkm/cont/arg/TypeCheck.h>
#include <vtkm/cont/ArrayHandle.h>
namespace vtkm {
namespace cont {
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 Type>
struct TypeCheck<TypeCheckTagArray, Type>
{
static const bool value =
vtkm::cont::internal::ArrayHandleCheck<Type>::type::value;
};
}
}
} // namespace vtkm::cont::arg
#endif //vtk_m_cont_arg_TypeCheckTagArray_h

@ -0,0 +1,50 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014. Los Alamos National Security
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_cont_arg_TypeCheckTagExecObject_h
#define vtk_m_cont_arg_TypeCheckTagExecObject_h
#include <vtkm/cont/arg/TypeCheck.h>
#include <vtkm/exec/ExecutionObjectBase.h>
#include <boost/type_traits/is_base_of.hpp>
namespace vtkm {
namespace cont {
namespace arg {
/// The ExecObject type check passes for any object that inherits from \c
/// ExecutionObjectBase. This is supposed to signify that the object can be
/// used in the execution environment although there is no way to verify that.
///
struct TypeCheckTagExecObject { };
template<typename Type>
struct TypeCheck<TypeCheckTagExecObject, Type>
{
static const bool value =
boost::is_base_of<vtkm::exec::ExecutionObjectBase, Type>::value;
};
}
}
} // namespace vtkm::cont::arg
#endif //vtk_m_cont_arg_TypeCheckTagExecObject_h

@ -22,6 +22,8 @@ set(unit_tests
UnitTestTransportArrayIn.cxx
UnitTestTransportArrayOut.cxx
UnitTestTransportExecObject.cxx
UnitTestTypeCheckArray.cxx
UnitTestTypeCheckExecObject.cxx
)
vtkm_unit_tests(SOURCES ${unit_tests})

@ -0,0 +1,74 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014. Los Alamos National Security
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#include <vtkm/cont/arg/TypeCheckTagArray.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleCompositeVector.h>
#include <vtkm/cont/ArrayHandleCounting.h>
#include <vtkm/cont/testing/Testing.h>
namespace {
struct TryArraysOfType
{
template<typename T>
void operator()(T) const
{
using vtkm::cont::arg::TypeCheck;
using vtkm::cont::arg::TypeCheckTagArray;
typedef vtkm::cont::ArrayHandle<T> StandardArray;
VTKM_TEST_ASSERT((TypeCheck<TypeCheckTagArray,StandardArray>::value),
"Standard array type check failed.");
typedef vtkm::cont::ArrayHandleCounting<T> CountingArray;
VTKM_TEST_ASSERT((TypeCheck<TypeCheckTagArray,CountingArray>::value),
"Counting array type check failed.");
typedef typename vtkm::cont::ArrayHandleCompositeVectorType<
StandardArray,CountingArray>::type CompositeArray;
VTKM_TEST_ASSERT((TypeCheck<TypeCheckTagArray,CompositeArray>::value),
"Composite array type check failed.");
// Just some type that is not a valid array.
typedef typename StandardArray::PortalControl NotAnArray;
VTKM_TEST_ASSERT(!(TypeCheck<TypeCheckTagArray,NotAnArray>::value),
"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.");
}
};
void TestCheckArray()
{
vtkm::testing::Testing::TryAllTypes(TryArraysOfType());
}
} // anonymous namespace
int UnitTestTypeCheckArray(int, char *[])
{
return vtkm::cont::testing::Testing::Run(TestCheckArray);
}

@ -0,0 +1,61 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014. Los Alamos National Security
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#include <vtkm/cont/arg/TypeCheckTagExecObject.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/testing/Testing.h>
namespace {
struct TestExecutionObject : vtkm::exec::ExecutionObjectBase { };
struct TestNotExecutionObject { };
void TestCheckExecObject()
{
std::cout << "Checking reporting of type checking exec object." << std::endl;
using vtkm::cont::arg::TypeCheck;
using vtkm::cont::arg::TypeCheckTagExecObject;
VTKM_TEST_ASSERT(
(TypeCheck<TypeCheckTagExecObject, TestExecutionObject>::value),
"Type check failed.");
VTKM_TEST_ASSERT(
!(TypeCheck<TypeCheckTagExecObject, TestNotExecutionObject>::value),
"Type check failed.");
VTKM_TEST_ASSERT(
!(TypeCheck<TypeCheckTagExecObject, vtkm::Id>::value),
"Type check failed.");
VTKM_TEST_ASSERT(
!(TypeCheck<TypeCheckTagExecObject, vtkm::cont::ArrayHandle<vtkm::Id> >::value),
"Type check failed.");
}
} // anonymous namespace
int UnitTestTypeCheckExecObject(int, char *[])
{
return vtkm::cont::testing::Testing::Run(TestCheckExecObject);
}

@ -26,26 +26,6 @@ namespace vtkm {
namespace cont {
namespace internal {
namespace detail {
template<typename ContinueFunctor>
struct DynamicArrayTransformCastAndCall
{
const ContinueFunctor &Continue;
VTKM_CONT_EXPORT
DynamicArrayTransformCastAndCall(const ContinueFunctor &continueFunc)
: Continue(continueFunc) { }
template<typename T>
VTKM_CONT_EXPORT
void operator()(const T &x) const {
this->Continue(x);
}
};
} // namespace detail
/// Tag used to identify an object that is a dynamic object that contains a
/// CastAndCall method that iterates over all possible dynamic choices to run
/// templated code.
@ -109,8 +89,7 @@ private:
const ContinueFunctor &continueFunc,
vtkm::cont::internal::DynamicTransformTagCastAndCall) const
{
dynamicInput.CastAndCall(
detail::DynamicArrayTransformCastAndCall<ContinueFunctor>(continueFunc));
dynamicInput.CastAndCall(continueFunc);
}
};

@ -24,6 +24,7 @@
#include <vtkm/cont/arg/TransportTagArrayIn.h>
#include <vtkm/cont/arg/TransportTagArrayOut.h>
#include <vtkm/cont/arg/TypeCheckTagArray.h>
#include <vtkm/exec/arg/FetchTagArrayDirectIn.h>
#include <vtkm/exec/arg/FetchTagArrayDirectOut.h>
@ -40,12 +41,14 @@ class WorkletMapField : public vtkm::worklet::internal::WorkletBase
public:
/// A control signature tag for input fields.
struct FieldIn {
typedef vtkm::cont::arg::TypeCheckTagArray TypeCheckTag;
typedef vtkm::cont::arg::TransportTagArrayIn TransportTag;
typedef vtkm::exec::arg::FetchTagArrayDirectIn FetchTag;
};
/// A control signature tag for output fields.
struct FieldOut {
typedef vtkm::cont::arg::TypeCheckTagArray TypeCheckTag;
typedef vtkm::cont::arg::TransportTagArrayOut TransportTag;
typedef vtkm::exec::arg::FetchTagArrayDirectOut FetchTag;
};

@ -24,8 +24,10 @@
#include <vtkm/internal/Invocation.h>
#include <vtkm/cont/DeviceAdapter.h>
#include <vtkm/cont/ErrorControlBadType.h>
#include <vtkm/cont/arg/Transport.h>
#include <vtkm/cont/arg/TypeCheck.h>
#include <vtkm/cont/internal/DynamicTransform.h>
@ -34,6 +36,9 @@
#include <boost/mpl/assert.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits/is_base_of.hpp>
#include <boost/utility/enable_if.hpp>
#include <sstream>
namespace vtkm {
namespace worklet {
@ -41,6 +46,76 @@ namespace internal {
namespace detail {
template<typename ContinueFunctor, typename TypeCheckTag>
struct DispatcherBaseTypeCheckFunctor
{
const ContinueFunctor &Continue;
vtkm::IdComponent ParameterIndex;
VTKM_CONT_EXPORT
DispatcherBaseTypeCheckFunctor(const ContinueFunctor &continueFunc,
vtkm::IdComponent parameterIndex)
: Continue(continueFunc), ParameterIndex(parameterIndex) { }
template<typename T>
VTKM_CONT_EXPORT
typename boost::enable_if_c<vtkm::cont::arg::TypeCheck<TypeCheckTag,T>::value>::type
operator()(const T &x) const
{
this->Continue(x);
}
// This code is actually taking an error found at compile-time and not
// reporting it until run-time. This seems strange at first, but this
// behavior is actually important. With dynamic arrays and similar dynamic
// classes, there may be types that are technically possible (such as using a
// vector where a scalar is expected) but in reality never happen. Thus, for
// these unsported combinations we just silently halt the compiler from
// attempting to create code for these errant conditions and throw a run-time
// error if one every tries to create one.
template<typename T>
VTKM_CONT_EXPORT
typename boost::disable_if_c<vtkm::cont::arg::TypeCheck<TypeCheckTag,T>::value>::type
operator()(const T &) const
{
std::stringstream message;
message << "Encountered bad type for parameter "
<< this->ParameterIndex
<< " when calling Invoke on a dispatcher.";
throw vtkm::cont::ErrorControlBadType(message.str());
}
};
struct DispatcherBaseDynamicTransform
{
vtkm::cont::internal::DynamicTransform BasicDynamicTransform;
vtkm::IdComponent *ParameterCounter;
VTKM_CONT_EXPORT
DispatcherBaseDynamicTransform(vtkm::IdComponent *parameterCounter)
: ParameterCounter(parameterCounter)
{
*this->ParameterCounter = 0;
}
template<typename ControlSignatureTag,
typename InputType,
typename ContinueFunctor>
VTKM_CONT_EXPORT
void operator()(const vtkm::Pair<ControlSignatureTag, InputType> &input,
const ContinueFunctor &continueFunc) const
{
(*this->ParameterCounter)++;
typedef DispatcherBaseTypeCheckFunctor<
ContinueFunctor, typename ControlSignatureTag::TypeCheckTag>
TypeCheckFunctor;
this->BasicDynamicTransform(input.second,
TypeCheckFunctor(continueFunc,
*this->ParameterCounter));
}
};
template<typename DispatcherBaseType>
struct DispatcherBaseDynamicTransformHelper
{
@ -122,8 +197,24 @@ protected:
BOOST_MPL_ASSERT(( boost::is_base_of<BaseWorkletType,WorkletType> ));
parameters.DynamicTransformCont(
vtkm::cont::internal::DynamicTransform(),
// 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,
// the check needs access to both the parameter (in the parameters
// argument) and the ControlSignature tags (in the ControlInterface type).
// To make this possible, we use the zip mechanism of FunctionInterface to
// combine these two separate function interfaces into a single
// FunctionInterface with each parameter being a Pair containing both
// the ControlSignature tag and the control object itself.
typedef typename vtkm::internal::FunctionInterfaceZipType<
ControlInterface, ParameterInterface>::type ZippedInterface;
ZippedInterface zippedInterface =
vtkm::internal::make_FunctionInterfaceZip(ControlInterface(),
parameters);
vtkm::IdComponent parameterIndexCounter;
zippedInterface.DynamicTransformCont(
detail::DispatcherBaseDynamicTransform(&parameterIndexCounter),
detail::DispatcherBaseDynamicTransformHelper<MyType>(this));
}
@ -179,7 +270,7 @@ private:
// object itself. To make it easier to work with each parameter, use the
// zip mechanism of FunctionInterface to combine the separate function
// interfaces of the ControlSignature and the parameters into one. This
// will make a Function interface with each parameter being a Pair
// will make a FunctionInterface with each parameter being a Pair
// containing both the ControlSignature tag and the control object itself.
typedef typename vtkm::internal::FunctionInterfaceZipType<
typename Invocation::ControlInterface,

@ -26,6 +26,7 @@
#include <vtkm/exec/arg/WorkIndex.h>
#include <vtkm/cont/arg/TransportTagExecObject.h>
#include <vtkm/cont/arg/TypeCheckTagExecObject.h>
namespace vtkm {
namespace worklet {
@ -57,6 +58,7 @@ public:
/// \c ControlSignature tag for execution object inputs.
struct ExecObject {
typedef vtkm::cont::arg::TypeCheckTagExecObject TypeCheckTag;
typedef vtkm::cont::arg::TransportTagExecObject TransportTag;
typedef vtkm::exec::arg::FetchTagExecObject FetchTag;
};

@ -43,6 +43,7 @@ struct TestExecObject
vtkm::Id *Array;
};
struct TestTypeCheckTag { };
struct TestTransportTag { };
struct TestFetchTagInput { };
struct TestFetchTagOutput { };
@ -53,6 +54,12 @@ namespace vtkm {
namespace cont {
namespace arg {
template<>
struct TypeCheck<TestTypeCheckTag, vtkm::Id *>
{
static const bool value = true;
};
template<>
struct Transport<TestTransportTag, vtkm::Id *, Device>
{
@ -122,10 +129,12 @@ class TestWorkletBase : public vtkm::worklet::internal::WorkletBase
{
public:
struct TestIn {
typedef TestTypeCheckTag TypeCheckTag;
typedef TestTransportTag TransportTag;
typedef TestFetchTagInput FetchTag;
};
struct TestOut {
typedef TestTypeCheckTag TypeCheckTag;
typedef TestTransportTag TransportTag;
typedef TestFetchTagOutput FetchTag;
};
@ -199,7 +208,8 @@ private:
void TestBasicInvoke()
{
std::cout << "Set up data." << std::endl;
std::cout << "Test basic invoke" << std::endl;
std::cout << " Set up data." << std::endl;
vtkm::Id inputArray[ARRAY_SIZE];
vtkm::Id outputArray[ARRAY_SIZE];
@ -209,11 +219,11 @@ void TestBasicInvoke()
outputArray[index] = 0xDEADDEAD;
}
std::cout << "Create and run dispatcher." << std::endl;
std::cout << " Create and run dispatcher." << std::endl;
TestDispatcher<TestWorklet> dispatcher;
dispatcher.Invoke(inputArray, outputArray);
std::cout << "Check output of invoke." << std::endl;
std::cout << " Check output of invoke." << std::endl;
for (vtkm::Id index = 0; index < ARRAY_SIZE; index++)
{
VTKM_TEST_ASSERT(outputArray[index] == TestValue(index, vtkm::Id()) + 1000,
@ -223,7 +233,8 @@ void TestBasicInvoke()
void TestInvokeWithError()
{
std::cout << "Set up data." << std::endl;
std::cout << "Test invoke with error raised" << std::endl;
std::cout << " Set up data." << std::endl;
vtkm::Id inputArray[ARRAY_SIZE];
vtkm::Id outputArray[ARRAY_SIZE];
@ -235,23 +246,58 @@ void TestInvokeWithError()
try
{
std::cout << "Create and run dispatcher that raises error." << std::endl;
std::cout << " Create and run dispatcher that raises error." << std::endl;
TestDispatcher<TestErrorWorklet> dispatcher;
dispatcher.Invoke(inputArray, outputArray);
VTKM_TEST_FAIL("Exception not thrown.");
}
catch (vtkm::cont::ErrorExecution error)
{
std::cout << "Got expected exception." << std::endl;
std::cout << " Got expected exception." << std::endl;
VTKM_TEST_ASSERT(error.GetMessage() == ERROR_MESSAGE,
"Got unexpected error message.");
}
}
void TestInvokeWithBadType()
{
std::cout << "Test invoke with bad type" << std::endl;
vtkm::Id array[ARRAY_SIZE];
TestDispatcher<TestWorklet> dispatcher;
try
{
std::cout << " First argument bad." << std::endl;
dispatcher.Invoke(NULL, array);
}
catch (vtkm::cont::ErrorControlBadType error)
{
std::cout << " Got expected exception." << std::endl;
std::cout << " " << error.GetMessage() << std::endl;
VTKM_TEST_ASSERT(error.GetMessage().find(" 1 ") != std::string::npos,
"Parameter index not named in error message.");
}
try
{
std::cout << " Second argument bad." << std::endl;
dispatcher.Invoke(array, NULL);
}
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.");
}
}
void TestDispatcherBase()
{
TestBasicInvoke();
TestInvokeWithError();
TestInvokeWithBadType();
}
} // anonymous namespace