mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-09-08 13:23:51 +00:00
Add ExecutionAndControlObjectBase
This is a subclass of ExecutionObject and a superset of its functionality. In addition to having a PrepareForExecution method, it also has a PrepareForControl method that gets an object appropriate for the control environment. This is helpful for situations where you need code to work in both environments, such as the functor in an ArrayHandleTransform. Also added several runtime checks for execution objects and execution and cotnrol objects.
This commit is contained in:
parent
62d3b9f4fb
commit
2b05487398
@ -12,8 +12,9 @@ might be that you need some lookup tables. Another might be you want to
|
||||
support a virtual object, which has to be initialized for a particular
|
||||
device. The standard way to implement this in VTK-m is to create an
|
||||
"executive object." This actually means that we create a wrapper around
|
||||
executive objects that inherits from `vtkm::cont::ExecutionObjectBase` that
|
||||
contains a `PrepareForExecution` method.
|
||||
executive objects that inherits from
|
||||
`vtkm::cont::ExecutionAndControlObjectBase` that contains a
|
||||
`PrepareForExecution` method and a `PrepareForControl` method.
|
||||
|
||||
As an example, consider the use case of a special `ArrayHandle` that takes
|
||||
the value in one array and returns the index of that value in another
|
||||
@ -56,12 +57,14 @@ struct FindValueFunctor
|
||||
|
||||
Simple enough, except that the type of `ArrayPortalType` depends on what
|
||||
device the functor runs on (not to mention its memory might need to be
|
||||
moved to different hardware). We can now solve this problem by creating an
|
||||
execution object to set this up for a device.
|
||||
moved to different hardware). We can now solve this problem by creating a
|
||||
functor objecgt set this up for a device. `ArrayHandle`s also need to be
|
||||
able to provide portals that run in the control environment, and for that
|
||||
we need a special version of the functor for the control environment.
|
||||
|
||||
``` cpp
|
||||
template <typename ArrayHandleType>
|
||||
struct FindValueExecutionObject : vtkm::cont::ExecutionObjectBase
|
||||
struct FindValueExecutionObject : vtkm::cont::ExecutionAndControlObjectBase
|
||||
{
|
||||
VTKM_IS_ARRAY_HANDLE(ArrayHandleType);
|
||||
|
||||
@ -83,6 +86,16 @@ struct FindValueExecutionObject : vtkm::cont::ExecutionObjectBase
|
||||
|
||||
return FunctorType(this->SortedArray.PrepareForInput(device));
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
FundValueFunctor<typename ArrayHandleType::PortalConstControl>
|
||||
PrepareForControl()
|
||||
{
|
||||
using FunctorType =
|
||||
FindValueFunctor<typename ArrayHandleType::PortalConstControl>
|
||||
|
||||
return FunctorType(this->SortedArray.GetPortalConstControl());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
16
docs/changelog/execution-and-control-objects.md
Normal file
16
docs/changelog/execution-and-control-objects.md
Normal file
@ -0,0 +1,16 @@
|
||||
# Add new execution and control objects
|
||||
|
||||
[Recent changes to execution objects](change-execution-object-creation.md)
|
||||
now have execution objects behave as factories that create an object
|
||||
specific for a particular device. Sometimes, you also need to be able to
|
||||
get an object that behaves properly in the control environment. For these
|
||||
cases, a sublcass to `vtkm::cont::ExecutionObjectBase` was created.
|
||||
|
||||
This subclass is called `vtkm::cont::ExecutionAndControlObjectBase`. In
|
||||
addition to the `PrepareForExecution` method required by its superclass,
|
||||
these objects also need to provide a `PrepareForControl` method to get an
|
||||
equivalent object that works in the control environment.
|
||||
|
||||
See [the changelog for execution objects in
|
||||
`ArrayHandleTransform`](array-handle-transform-exec-object.md) for an
|
||||
example of using a `vtkm::cont::ExecutionAndControlObjectBase`.
|
@ -38,24 +38,25 @@ template <typename Device, typename T>
|
||||
inline auto DoPrepareArgForExec(T&& object, std::true_type)
|
||||
-> decltype(std::declval<T>().PrepareForExecution(Device()))
|
||||
{
|
||||
VTKM_IS_EXECUTION_OBJECT(T);
|
||||
return object.PrepareForExecution(Device{});
|
||||
}
|
||||
|
||||
template <typename Device, typename T>
|
||||
inline T&& DoPrepareArgForExec(T&& object, std::false_type)
|
||||
{
|
||||
static_assert(!vtkm::cont::internal::IsExecutionObjectBase<T>::value,
|
||||
"Internal error: failed to detect execution object.");
|
||||
return std::forward<T>(object);
|
||||
}
|
||||
|
||||
template <typename Device, typename T>
|
||||
auto PrepareArgForExec(T&& object) -> decltype(DoPrepareArgForExec<Device>(
|
||||
std::forward<T>(object),
|
||||
typename std::is_base_of<vtkm::cont::ExecutionObjectBase, typename std::decay<T>::type>::type{}))
|
||||
auto PrepareArgForExec(T&& object)
|
||||
-> decltype(DoPrepareArgForExec<Device>(std::forward<T>(object),
|
||||
vtkm::cont::internal::IsExecutionObjectBase<T>{}))
|
||||
{
|
||||
return DoPrepareArgForExec<Device>(
|
||||
std::forward<T>(object),
|
||||
typename std::is_base_of<vtkm::cont::ExecutionObjectBase,
|
||||
typename std::decay<T>::type>::type{});
|
||||
return DoPrepareArgForExec<Device>(std::forward<T>(object),
|
||||
vtkm::cont::internal::IsExecutionObjectBase<T>{});
|
||||
}
|
||||
|
||||
struct CopyFunctor
|
||||
|
@ -25,9 +25,8 @@
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
#include <vtkm/cont/ErrorBadType.h>
|
||||
#include <vtkm/cont/ErrorInternal.h>
|
||||
#include <vtkm/cont/ExecutionObjectBase.h>
|
||||
#include <vtkm/cont/ExecutionAndControlObjectBase.h>
|
||||
#include <vtkm/cont/RuntimeDeviceTracker.h>
|
||||
#include <vtkm/cont/serial/DeviceAdapterSerial.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
@ -181,14 +180,17 @@ namespace cont
|
||||
namespace internal
|
||||
{
|
||||
|
||||
template <typename ProvidedFunctorType, typename Device, typename FunctorIsExecObject>
|
||||
template <typename ProvidedFunctorType, typename FunctorIsExecContObject>
|
||||
struct TransformFunctorManagerImpl;
|
||||
|
||||
template <typename ProvidedFunctorType, typename Device>
|
||||
struct TransformFunctorManagerImpl<ProvidedFunctorType, Device, std::false_type>
|
||||
template <typename ProvidedFunctorType>
|
||||
struct TransformFunctorManagerImpl<ProvidedFunctorType, std::false_type>
|
||||
{
|
||||
VTKM_STATIC_ASSERT_MSG(!vtkm::cont::internal::IsExecutionObjectBase<ProvidedFunctorType>::value,
|
||||
"Must use an ExecutionAndControlObject instead of an ExecutionObject.");
|
||||
|
||||
ProvidedFunctorType Functor;
|
||||
using FunctorType = ProvidedFunctorType;
|
||||
ProvidedFunctorType Functor;
|
||||
|
||||
TransformFunctorManagerImpl() = default;
|
||||
|
||||
@ -199,14 +201,23 @@ struct TransformFunctorManagerImpl<ProvidedFunctorType, Device, std::false_type>
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
FunctorType GetFunctor() const { return this->Functor; }
|
||||
ProvidedFunctorType PrepareForControl() const { return this->Functor; }
|
||||
|
||||
template <typename Device>
|
||||
VTKM_CONT ProvidedFunctorType PrepareForExecution(Device) const
|
||||
{
|
||||
return this->Functor;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ProvidedFunctorType, typename Device>
|
||||
struct TransformFunctorManagerImpl<ProvidedFunctorType, Device, std::true_type>
|
||||
template <typename ProvidedFunctorType>
|
||||
struct TransformFunctorManagerImpl<ProvidedFunctorType, std::true_type>
|
||||
{
|
||||
using FunctorType = decltype(std::declval<ProvidedFunctorType>().PrepareForExecution(Device()));
|
||||
VTKM_IS_EXECUTION_AND_CONTROL_OBJECT(ProvidedFunctorType);
|
||||
|
||||
ProvidedFunctorType Functor;
|
||||
// using FunctorType = decltype(std::declval<ProvidedFunctorType>().PrepareForControl());
|
||||
using FunctorType = decltype(Functor.PrepareForControl());
|
||||
|
||||
TransformFunctorManagerImpl() = default;
|
||||
|
||||
@ -217,20 +228,28 @@ struct TransformFunctorManagerImpl<ProvidedFunctorType, Device, std::true_type>
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
FunctorType GetFunctor() const { return this->Functor.PrepareForExecution(Device()); }
|
||||
auto PrepareForControl() const -> decltype(this->Functor.PrepareForControl())
|
||||
{
|
||||
return this->Functor.PrepareForControl();
|
||||
}
|
||||
|
||||
template <typename Device>
|
||||
VTKM_CONT auto PrepareForExecution(Device device) const
|
||||
-> decltype(this->Functor.PrepareForExecution(device))
|
||||
{
|
||||
return this->Functor.PrepareForExecution(device);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ProvidedFunctorType, typename Device = vtkm::cont::DeviceAdapterTagSerial>
|
||||
template <typename ProvidedFunctorType>
|
||||
struct TransformFunctorManager
|
||||
: TransformFunctorManagerImpl<
|
||||
ProvidedFunctorType,
|
||||
Device,
|
||||
typename std::is_base_of<vtkm::cont::ExecutionObjectBase, ProvidedFunctorType>::type>
|
||||
typename vtkm::cont::internal::IsExecutionAndControlObjectBase<ProvidedFunctorType>::type>
|
||||
{
|
||||
using Superclass = TransformFunctorManagerImpl<
|
||||
ProvidedFunctorType,
|
||||
Device,
|
||||
typename std::is_base_of<vtkm::cont::ExecutionObjectBase, ProvidedFunctorType>::type>;
|
||||
typename vtkm::cont::internal::IsExecutionAndControlObjectBase<ProvidedFunctorType>::type>;
|
||||
using FunctorType = typename Superclass::FunctorType;
|
||||
|
||||
VTKM_CONT TransformFunctorManager() = default;
|
||||
@ -242,13 +261,6 @@ struct TransformFunctorManager
|
||||
{
|
||||
}
|
||||
|
||||
template <typename OtherDevice>
|
||||
VTKM_CONT TransformFunctorManager(
|
||||
const TransformFunctorManager<ProvidedFunctorType, OtherDevice>& other)
|
||||
: Superclass(other.Functor)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
using TransformedValueType = decltype(std::declval<FunctorType>()(ValueType{}));
|
||||
};
|
||||
@ -312,7 +324,7 @@ public:
|
||||
VTKM_ASSERT(this->Valid);
|
||||
vtkm::cont::ScopedGlobalRuntimeDeviceTracker trackerScope;
|
||||
vtkm::cont::GetGlobalRuntimeDeviceTracker().ForceDevice(vtkm::cont::DeviceAdapterTagSerial());
|
||||
return PortalConstType(this->Array.GetPortalConstControl(), this->Functor.GetFunctor());
|
||||
return PortalConstType(this->Array.GetPortalConstControl(), this->Functor.PrepareForControl());
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
@ -405,8 +417,8 @@ public:
|
||||
vtkm::cont::ScopedGlobalRuntimeDeviceTracker trackerScope;
|
||||
vtkm::cont::GetGlobalRuntimeDeviceTracker().ForceDevice(vtkm::cont::DeviceAdapterTagSerial());
|
||||
return PortalType(this->Array.GetPortalControl(),
|
||||
this->Functor.GetFunctor(),
|
||||
this->InverseFunctor.GetFunctor());
|
||||
this->Functor.PrepareForControl(),
|
||||
this->InverseFunctor.PrepareForControl());
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
@ -416,8 +428,8 @@ public:
|
||||
vtkm::cont::ScopedGlobalRuntimeDeviceTracker trackerScope;
|
||||
vtkm::cont::GetGlobalRuntimeDeviceTracker().ForceDevice(vtkm::cont::DeviceAdapterTagSerial());
|
||||
return PortalConstType(this->Array.GetPortalConstControl(),
|
||||
this->Functor.GetFunctor(),
|
||||
this->InverseFunctor.GetFunctor());
|
||||
this->Functor.PrepareForControl(),
|
||||
this->InverseFunctor.PrepareForControl());
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
@ -470,7 +482,7 @@ class ArrayTransfer<typename StorageTagTransform<ArrayHandleType, FunctorType>::
|
||||
Device>
|
||||
{
|
||||
using StorageTag = StorageTagTransform<ArrayHandleType, FunctorType>;
|
||||
using FunctorManager = TransformFunctorManager<FunctorType, Device>;
|
||||
using FunctorManager = TransformFunctorManager<FunctorType>;
|
||||
|
||||
public:
|
||||
using ValueType = typename StorageTagTransform<ArrayHandleType, FunctorType>::ValueType;
|
||||
@ -499,7 +511,8 @@ public:
|
||||
VTKM_CONT
|
||||
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData))
|
||||
{
|
||||
return PortalConstExecution(this->Array.PrepareForInput(Device()), this->Functor.GetFunctor());
|
||||
return PortalConstExecution(this->Array.PrepareForInput(Device()),
|
||||
this->Functor.PrepareForExecution(Device()));
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
@ -548,8 +561,8 @@ class ArrayTransfer<
|
||||
Device>
|
||||
{
|
||||
using StorageTag = StorageTagTransform<ArrayHandleType, FunctorType, InverseFunctorType>;
|
||||
using FunctorManager = TransformFunctorManager<FunctorType, Device>;
|
||||
using InverseFunctorManager = TransformFunctorManager<InverseFunctorType, Device>;
|
||||
using FunctorManager = TransformFunctorManager<FunctorType>;
|
||||
using InverseFunctorManager = TransformFunctorManager<InverseFunctorType>;
|
||||
|
||||
public:
|
||||
using ValueType = typename StorageTagTransform<ArrayHandleType, FunctorType>::ValueType;
|
||||
@ -584,24 +597,24 @@ public:
|
||||
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData))
|
||||
{
|
||||
return PortalConstExecution(this->Array.PrepareForInput(Device()),
|
||||
this->Functor.GetFunctor(),
|
||||
this->InverseFunctor.GetFunctor());
|
||||
this->Functor.PrepareForExecution(Device()),
|
||||
this->InverseFunctor.PrepareForExecution(Device()));
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
PortalExecution PrepareForInPlace(bool& vtkmNotUsed(updateData))
|
||||
{
|
||||
return PortalExecution(this->Array.PrepareForInPlace(Device()),
|
||||
this->Functor.GetFunctor(),
|
||||
this->InverseFunctor.GetFunctor());
|
||||
this->Functor.PrepareForExecution(Device()),
|
||||
this->InverseFunctor.PrepareForExecution(Device()));
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
PortalExecution PrepareForOutput(vtkm::Id numberOfValues)
|
||||
{
|
||||
return PortalExecution(this->Array.PrepareForOutput(numberOfValues, Device()),
|
||||
this->Functor.GetFunctor(),
|
||||
this->InverseFunctor.GetFunctor());
|
||||
this->Functor.PrepareForExecution(Device()),
|
||||
this->InverseFunctor.PrepareForExecution(Device()));
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
|
@ -83,6 +83,7 @@ set(headers
|
||||
ErrorFilterExecution.h
|
||||
ErrorExecution.h
|
||||
ErrorInternal.h
|
||||
ExecutionAndControlObjectBase.h
|
||||
ExecutionObjectBase.h
|
||||
Field.h
|
||||
FieldRangeCompute.h
|
||||
|
82
vtkm/cont/ExecutionAndControlObjectBase.h
Normal file
82
vtkm/cont/ExecutionAndControlObjectBase.h
Normal file
@ -0,0 +1,82 @@
|
||||
//============================================================================
|
||||
// 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 2018 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
|
||||
// Copyright 2018 UT-Battelle, LLC.
|
||||
// Copyright 2018 Los Alamos National Security.
|
||||
//
|
||||
// Under the terms of Contract DE-NA0003525 with NTESS,
|
||||
// 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_ExecutionAndControlObjectBase_h
|
||||
#define vtk_m_cont_ExecutionAndControlObjectBase_h
|
||||
|
||||
#include <vtkm/cont/ExecutionObjectBase.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace cont
|
||||
{
|
||||
|
||||
/// Base \c ExecutionAndControlObjectBase class. These are objects that behave
|
||||
/// as execution objects but can also be use din the control environment.
|
||||
/// Any subclass of \c ExecutionAndControlObjectBase must implement a
|
||||
/// \c PrepareForExecution method that takes a device adapter tag and returns
|
||||
/// an object for that device as well as a \c PrepareForControl that simply
|
||||
/// returns an object that works in the control environment.
|
||||
///
|
||||
struct ExecutionAndControlObjectBase : vtkm::cont::ExecutionObjectBase
|
||||
{
|
||||
};
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
struct CheckPrepareForControl
|
||||
{
|
||||
template <typename T>
|
||||
static auto check(T* p) -> decltype(p->PrepareForControl(), std::true_type());
|
||||
|
||||
template <typename T>
|
||||
static auto check(...) -> std::false_type;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T>
|
||||
using IsExecutionAndControlObjectBase =
|
||||
std::is_base_of<vtkm::cont::ExecutionAndControlObjectBase, typename std::decay<T>::type>;
|
||||
|
||||
template <typename T>
|
||||
struct HasPrepareForControl
|
||||
: decltype(detail::CheckPrepareForControl::check<typename std::decay<T>::type>(nullptr))
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
}
|
||||
} // namespace vtkm::cont
|
||||
|
||||
/// Checks that the argument is a proper execution object.
|
||||
///
|
||||
#define VTKM_IS_EXECUTION_AND_CONTROL_OBJECT(execObject) \
|
||||
static_assert(::vtkm::cont::internal::IsExecutionAndControlObjectBase<execObject>::value, \
|
||||
"Provided type is not a subclass of vtkm::cont::ExecutionAndControlObjectBase."); \
|
||||
static_assert(::vtkm::cont::internal::HasPrepareForExecution<execObject>::value, \
|
||||
"Provided type does not have requisite PrepareForExecution method."); \
|
||||
static_assert(::vtkm::cont::internal::HasPrepareForControl<execObject>::value, \
|
||||
"Provided type does not have requisite PrepareForControl method.")
|
||||
|
||||
#endif //vtk_m_cont_ExecutionAndControlObjectBase_h
|
@ -19,21 +19,75 @@
|
||||
//============================================================================
|
||||
#ifndef vtk_m_cont_ExecutionObjectBase_h
|
||||
#define vtk_m_cont_ExecutionObjectBase_h
|
||||
|
||||
#include <vtkm/Types.h>
|
||||
|
||||
#include <vtkm/cont/DeviceAdapter.h>
|
||||
|
||||
#if ((VTKM_DEVICE_ADAPTER > 0) && (VTKM_DEVICE_ADAPTER < VTKM_MAX_DEVICE_ADAPTER_ID))
|
||||
// Use the default device adapter tag for testing whether execution objects are valid.
|
||||
#define VTK_M_DEVICE_ADAPTER_TO_TEST_EXEC_OBJECT VTKM_DEFAULT_DEVICE_ADAPTER_TAG
|
||||
#else
|
||||
// The default device adapter is invalid. Perhaps the error device adapter is being used.
|
||||
// In this case, try the serial device adapter instead. It should always be valid.
|
||||
#include <vtkm/cont/serial/DeviceAdapterSerial.h>
|
||||
#define VTK_M_DEVICE_ADAPTER_TO_TEST_EXEC_OBJECT ::vtkm::cont::DeviceAdapterTagSerial
|
||||
#endif
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace cont
|
||||
{
|
||||
|
||||
/// Base \c ExecutionObjectBase for execution objects to inherit from so that
|
||||
/// you can use an arbitrary object as a parameter in an execution environment
|
||||
/// function. Any method you want to use on the execution side must have the
|
||||
/// VTKM_EXEC modifier.
|
||||
/// \tparam Device
|
||||
|
||||
class ExecutionObjectBase
|
||||
/// function. Any subclass of \c ExecutionObjectBase must implement a
|
||||
/// \c PrepareForExecution method that takes a device adapter tag and returns
|
||||
/// an object for that device.
|
||||
///
|
||||
struct ExecutionObjectBase
|
||||
{
|
||||
};
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
struct CheckPrepareForExecution
|
||||
{
|
||||
template <typename T>
|
||||
static auto check(T* p)
|
||||
-> decltype(p->PrepareForExecution(VTK_M_DEVICE_ADAPTER_TO_TEST_EXEC_OBJECT()),
|
||||
std::true_type());
|
||||
|
||||
template <typename T>
|
||||
static auto check(...) -> std::false_type;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T>
|
||||
using IsExecutionObjectBase =
|
||||
std::is_base_of<vtkm::cont::ExecutionObjectBase, typename std::decay<T>::type>;
|
||||
|
||||
template <typename T>
|
||||
struct HasPrepareForExecution
|
||||
: decltype(detail::CheckPrepareForExecution::check<typename std::decay<T>::type>(nullptr))
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
}
|
||||
} // namespace vtkm::cont
|
||||
|
||||
/// Checks that the argument is a proper execution object.
|
||||
///
|
||||
#define VTKM_IS_EXECUTION_OBJECT(execObject) \
|
||||
static_assert(::vtkm::cont::internal::IsExecutionObjectBase<execObject>::value, \
|
||||
"Provided type is not a subclass of vtkm::cont::ExecutionObjectBase."); \
|
||||
static_assert(::vtkm::cont::internal::HasPrepareForExecution<execObject>::value, \
|
||||
"Provided type does not have requisite PrepareForExecution method.")
|
||||
|
||||
#endif //vtk_m_cont_ExecutionObjectBase_h
|
||||
|
@ -48,10 +48,8 @@ struct Transport<vtkm::cont::arg::TransportTagExecObject, ContObjectType, Device
|
||||
{
|
||||
// If you get a compile error here, it means you tried to use an object that is not an execution
|
||||
// object as an argument that is expected to be one. All execution objects are expected to
|
||||
// inherit from vtkm::cont::ExecutionObjectBase.
|
||||
VTKM_STATIC_ASSERT_MSG(
|
||||
(std::is_base_of<vtkm::cont::ExecutionObjectBase, ContObjectType>::value),
|
||||
"All execution objects are expected to inherit from vtkm::cont::ExecutionObjectBase");
|
||||
// inherit from vtkm::cont::ExecutionObjectBase and have a PrepareForExecution method.
|
||||
VTKM_IS_EXECUTION_OBJECT(ContObjectType);
|
||||
|
||||
using ExecObjectType = decltype(std::declval<ContObjectType>().PrepareForExecution(Device()));
|
||||
template <typename InputDomainType>
|
||||
|
@ -46,7 +46,7 @@ struct TypeCheckTagExecObject
|
||||
template <typename Type>
|
||||
struct TypeCheck<TypeCheckTagExecObject, Type>
|
||||
{
|
||||
static constexpr bool value = std::is_base_of<vtkm::cont::ExecutionObjectBase, Type>::value;
|
||||
static constexpr bool value = vtkm::cont::internal::IsExecutionObjectBase<Type>::value;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,13 @@
|
||||
namespace
|
||||
{
|
||||
|
||||
struct NotAnExecutionObject
|
||||
{
|
||||
};
|
||||
struct InvalidExecutionObject : vtkm::cont::ExecutionObjectBase
|
||||
{
|
||||
};
|
||||
|
||||
template <typename Device>
|
||||
struct ExecutionObject
|
||||
{
|
||||
@ -51,6 +58,7 @@ struct TestExecutionObject : public vtkm::cont::ExecutionObjectBase
|
||||
return object;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Device>
|
||||
struct TestKernel : public vtkm::exec::FunctorBase
|
||||
{
|
||||
@ -83,6 +91,21 @@ void TryExecObjectTransport(Device)
|
||||
|
||||
void TestExecObjectTransport()
|
||||
{
|
||||
std::cout << "Checking ExecObject queries." << std::endl;
|
||||
VTKM_TEST_ASSERT(!vtkm::cont::internal::IsExecutionObjectBase<NotAnExecutionObject>::value,
|
||||
"Bad query");
|
||||
VTKM_TEST_ASSERT(vtkm::cont::internal::IsExecutionObjectBase<InvalidExecutionObject>::value,
|
||||
"Bad query");
|
||||
VTKM_TEST_ASSERT(vtkm::cont::internal::IsExecutionObjectBase<TestExecutionObject>::value,
|
||||
"Bad query");
|
||||
|
||||
VTKM_TEST_ASSERT(!vtkm::cont::internal::HasPrepareForExecution<NotAnExecutionObject>::value,
|
||||
"Bad query");
|
||||
VTKM_TEST_ASSERT(!vtkm::cont::internal::HasPrepareForExecution<InvalidExecutionObject>::value,
|
||||
"Bad query");
|
||||
VTKM_TEST_ASSERT(vtkm::cont::internal::HasPrepareForExecution<TestExecutionObject>::value,
|
||||
"Bad query");
|
||||
|
||||
std::cout << "Trying ExecObject transport with serial device." << std::endl;
|
||||
TryExecObjectTransport(vtkm::cont::DeviceAdapterTagSerial());
|
||||
}
|
||||
|
@ -162,7 +162,7 @@ struct VirtualTransformFunctor : VirtualTransformFunctorBase<ValueType>
|
||||
};
|
||||
|
||||
template <typename ValueType>
|
||||
struct TransformExecObject : public vtkm::cont::ExecutionObjectBase
|
||||
struct TransformExecObject : public vtkm::cont::ExecutionAndControlObjectBase
|
||||
{
|
||||
vtkm::cont::VirtualObjectHandle<VirtualTransformFunctorBase<ValueType>> VirtualFunctor;
|
||||
|
||||
@ -178,15 +178,14 @@ struct TransformExecObject : public vtkm::cont::ExecutionObjectBase
|
||||
this->VirtualFunctor.Reset(new VirtualTransformFunctor<ValueType, FunctorType>(functor));
|
||||
}
|
||||
|
||||
template <typename DeviceAdapterTag>
|
||||
struct ExecutionObject
|
||||
struct FunctorWrapper
|
||||
{
|
||||
const VirtualTransformFunctorBase<ValueType>* FunctorPointer;
|
||||
|
||||
ExecutionObject() = default;
|
||||
FunctorWrapper() = default;
|
||||
|
||||
VTKM_CONT
|
||||
ExecutionObject(const VirtualTransformFunctorBase<ValueType>* functorPointer)
|
||||
FunctorWrapper(const VirtualTransformFunctorBase<ValueType>* functorPointer)
|
||||
: FunctorPointer(functorPointer)
|
||||
{
|
||||
}
|
||||
@ -199,9 +198,14 @@ struct TransformExecObject : public vtkm::cont::ExecutionObjectBase
|
||||
};
|
||||
|
||||
template <typename DeviceAdapterTag>
|
||||
VTKM_CONT ExecutionObject<DeviceAdapterTag> PrepareForExecution(DeviceAdapterTag device) const
|
||||
VTKM_CONT FunctorWrapper PrepareForExecution(DeviceAdapterTag device) const
|
||||
{
|
||||
return ExecutionObject<DeviceAdapterTag>(this->VirtualFunctor.PrepareForExecution(device));
|
||||
return FunctorWrapper(this->VirtualFunctor.PrepareForExecution(device));
|
||||
}
|
||||
|
||||
VTKM_CONT FunctorWrapper PrepareForControl() const
|
||||
{
|
||||
return FunctorWrapper(this->VirtualFunctor.Get());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -22,8 +22,6 @@
|
||||
|
||||
#include <vtkm/exec/arg/testing/ThreadIndicesTesting.h>
|
||||
|
||||
#include <vtkm/cont/ExecutionObjectBase.h>
|
||||
|
||||
#include <vtkm/testing/Testing.h>
|
||||
|
||||
#define EXPECTED_NUMBER 67
|
||||
@ -31,7 +29,7 @@
|
||||
namespace
|
||||
{
|
||||
|
||||
struct TestExecutionObject : public vtkm::cont::ExecutionObjectBase
|
||||
struct TestExecutionObject
|
||||
{
|
||||
TestExecutionObject()
|
||||
: Number(static_cast<vtkm::Int32>(0xDEADDEAD))
|
||||
|
Loading…
Reference in New Issue
Block a user