From 5ef4e7eeee2df84600bdc54277744f4f186fc083 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Wed, 6 Jan 2021 10:24:42 -0700 Subject: [PATCH 1/2] Make new style of ArrayHandle the expected style What was previously declared as `ArrayHandleNewStyle` is now just the implementation of `ArrayHandle`. The old implementation of `ArrayHandle` has been moved to `ArrayHandleDeprecated`, and `ArrayHandle`s still using this implementation must declare `VTKM_ARRAY_HANDLE_DEPRECATED` to use it. --- vtkm/cont/ArrayCopy.h | 9 +- vtkm/cont/ArrayHandle.h | 782 +--------- vtkm/cont/ArrayHandle.hxx | 596 -------- vtkm/cont/ArrayHandleBasic.cxx | 10 +- vtkm/cont/ArrayHandleBasic.h | 19 +- vtkm/cont/ArrayHandleBitField.h | 3 - vtkm/cont/ArrayHandleCartesianProduct.h | 5 - vtkm/cont/ArrayHandleCast.h | 3 - vtkm/cont/ArrayHandleCompositeVector.h | 3 - vtkm/cont/ArrayHandleConcatenate.h | 3 - vtkm/cont/ArrayHandleConstant.h | 3 - vtkm/cont/ArrayHandleCounting.h | 3 - vtkm/cont/ArrayHandleDecorator.h | 5 - vtkm/cont/ArrayHandleDiscard.h | 4 - vtkm/cont/ArrayHandleExtractComponent.h | 3 - vtkm/cont/ArrayHandleExtrudeCoords.h | 6 + vtkm/cont/ArrayHandleExtrudeField.h | 5 + vtkm/cont/ArrayHandleGroupVec.h | 3 - vtkm/cont/ArrayHandleGroupVecVariable.h | 3 - vtkm/cont/ArrayHandleImplicit.h | 5 - vtkm/cont/ArrayHandleIndex.h | 3 - vtkm/cont/ArrayHandleMultiplexer.h | 3 - vtkm/cont/ArrayHandlePermutation.h | 3 - vtkm/cont/ArrayHandleRecombineVec.h | 3 - vtkm/cont/ArrayHandleReverse.h | 3 - vtkm/cont/ArrayHandleSOA.h | 3 - vtkm/cont/ArrayHandleStride.cxx | 22 +- vtkm/cont/ArrayHandleStride.h | 27 +- vtkm/cont/ArrayHandleTransform.h | 3 - .../cont/ArrayHandleUniformPointCoordinates.h | 3 - vtkm/cont/ArrayHandleView.h | 4 - vtkm/cont/ArrayHandleVirtual.h | 8 +- vtkm/cont/ArrayHandleZip.h | 4 - vtkm/cont/CMakeLists.txt | 1 - vtkm/cont/StorageExtrude.h | 3 + vtkm/cont/StorageVirtual.h | 2 + vtkm/cont/StorageVirtual.hxx | 3 +- vtkm/cont/internal/ArrayHandleDeprecated.h | 1354 +++++++++++++++++ vtkm/cont/internal/CMakeLists.txt | 1 + vtkm/cont/internal/StorageDeprecated.h | 8 +- vtkm/cont/internal/testing/UnitTestBuffer.cxx | 1 + vtkm/cont/testing/TestingDeviceAdapter.h | 1 + 42 files changed, 1457 insertions(+), 1479 deletions(-) delete mode 100644 vtkm/cont/ArrayHandle.hxx create mode 100644 vtkm/cont/internal/ArrayHandleDeprecated.h diff --git a/vtkm/cont/ArrayCopy.h b/vtkm/cont/ArrayCopy.h index 06f588ea9..ebf75f2a9 100644 --- a/vtkm/cont/ArrayCopy.h +++ b/vtkm/cont/ArrayCopy.h @@ -16,6 +16,8 @@ #include #include +#include + #include // TODO: When virtual arrays are available, compile the implementation in a .cxx/.cu file. Common @@ -149,11 +151,12 @@ VTKM_CONT void ArrayCopy(const vtkm::cont::ArrayHandle& "Cannot copy to a read-only array with a different " "type than the source."); - using IsNewStyle = - std::is_base_of, InArrayType>; + using IsOldStyle = + std::is_base_of, + InArrayType>; // Static dispatch cases 1 & 2 - detail::ArrayCopyImpl(source, destination, std::integral_constant{}); + detail::ArrayCopyImpl(source, destination, std::integral_constant{}); } // Forward declaration diff --git a/vtkm/cont/ArrayHandle.h b/vtkm/cont/ArrayHandle.h index a37e0e40d..28039e989 100644 --- a/vtkm/cont/ArrayHandle.h +++ b/vtkm/cont/ArrayHandle.h @@ -17,7 +17,6 @@ #include #include -#include #include #include #include @@ -33,10 +32,7 @@ #include #include -#include -#include #include -#include namespace vtkm { @@ -256,652 +252,6 @@ struct GetTypeInParentheses #define VTKM_ARRAY_HANDLE_SUBCLASS_NT(classname, superclass) \ VTK_M_ARRAY_HANDLE_SUBCLASS_IMPL(classname, (classname), superclass, ) -/// \brief Manages an array-worth of data. -/// -/// \c ArrayHandle manages as array of data that can be manipulated by VTKm -/// algorithms. The \c ArrayHandle may have up to two copies of the array, one -/// for the control environment and one for the execution environment, although -/// depending on the device and how the array is being used, the \c ArrayHandle -/// will only have one copy when possible. -/// -/// An ArrayHandle can be constructed one of two ways. Its default construction -/// creates an empty, unallocated array that can later be allocated and filled -/// either by the user or a VTKm algorithm. The \c ArrayHandle can also be -/// constructed with iterators to a user's array. In this case the \c -/// ArrayHandle will keep a reference to this array but will throw an exception -/// if asked to re-allocate to a larger size. -/// -/// \c ArrayHandle behaves like a shared smart pointer in that when it is copied -/// each copy holds a reference to the same array. These copies are reference -/// counted so that when all copies of the \c ArrayHandle are destroyed, any -/// allocated memory is released. -/// -/// -template -class VTKM_ALWAYS_EXPORT ArrayHandle : public internal::ArrayHandleBase -{ -private: - // Basic storage is specialized; this template should not be instantiated - // for it. Specialization is in ArrayHandleBasicImpl.h - static_assert(!std::is_same::value, - "StorageTagBasic should not use this implementation."); - - using ExecutionManagerType = - vtkm::cont::internal::ArrayHandleExecutionManagerBase; - - using MutexType = std::mutex; - using LockType = std::unique_lock; - - mutable vtkm::cont::internal::Buffer BufferAsStorageWrapper; - -public: - using StorageType = vtkm::cont::internal::Storage; - using ValueType = T; - using StorageTag = StorageTag_; - using WritePortalType = typename StorageType::PortalType; - using ReadPortalType = typename StorageType::PortalConstType; - template - struct ExecutionTypes - { - using Portal = typename ExecutionManagerType::template ExecutionTypes::Portal; - using PortalConst = - typename ExecutionManagerType::template ExecutionTypes::PortalConst; - }; - - using PortalControl VTKM_DEPRECATED(1.6, "Use ArrayHandle::WritePortalType instead.") = - typename StorageType::PortalType; - using PortalConstControl VTKM_DEPRECATED(1.6, "Use ArrayHandle::ReadPortalType instead.") = - typename StorageType::PortalConstType; - - // Handle the fact that the ArrayHandle design has changed. - VTKM_STATIC_ASSERT_MSG((std::is_same::value), - "ArrayHandle design has changed. To support old-style arrays, have the " - "Storage implementation subclass StorageDeprecated."); - VTKM_CONT static constexpr vtkm::IdComponent GetNumberOfBuffers() { return 1; } - VTKM_CONT vtkm::cont::internal::Buffer* GetBuffers() const - { - this->BufferAsStorageWrapper.SetMetaData(*this); - return &this->BufferAsStorageWrapper; - } - - VTKM_CONT ArrayHandle(const vtkm::cont::internal::Buffer* buffers) - { - VTKM_ASSERT(buffers[0].MetaDataIsType()); - *this = buffers[0].GetMetaData(); - } - - /// Constructs an empty ArrayHandle. Typically used for output or - /// intermediate arrays that will be filled by a VTKm algorithm. - /// - VTKM_CONT ArrayHandle(); - - /// Copy constructor. - /// - /// Implemented so that it is defined exclusively in the control environment. - /// If there is a separate device for the execution environment (for example, - /// with CUDA), then the automatically generated copy constructor could be - /// created for all devices, and it would not be valid for all devices. - /// - ArrayHandle(const vtkm::cont::ArrayHandle& src); - - /// Move constructor. - /// - /// Implemented so that it is defined exclusively in the control environment. - /// If there is a separate device for the execution environment (for example, - /// with CUDA), then the automatically generated move constructor could be - /// created for all devices, and it would not be valid for all devices. - /// - ArrayHandle(vtkm::cont::ArrayHandle&& src) noexcept; - - /// Special constructor for subclass specializations that need to set the - /// initial state of the control array. When this constructor is used, it - /// is assumed that the control array is valid. - /// - ArrayHandle(const StorageType& storage); - - - /// Special constructor for subclass specializations that need to set the - /// initial state of the control array. When this constructor is used, it - /// is assumed that the control array is valid. - /// - ArrayHandle(StorageType&& storage) noexcept; - - /// Destructs an empty ArrayHandle. - /// - /// Implemented so that it is defined exclusively in the control environment. - /// If there is a separate device for the execution environment (for example, - /// with CUDA), then the automatically generated destructor could be - /// created for all devices, and it would not be valid for all devices. - /// - ~ArrayHandle(); - - /// \brief Copies an ArrayHandle - /// - VTKM_CONT - vtkm::cont::ArrayHandle& operator=( - const vtkm::cont::ArrayHandle& src); - - /// \brief Move and Assignment of an ArrayHandle - /// - VTKM_CONT - vtkm::cont::ArrayHandle& operator=( - vtkm::cont::ArrayHandle&& src) noexcept; - - /// Like a pointer, two \c ArrayHandles are considered equal if they point - /// to the same location in memory. - /// - VTKM_CONT - bool operator==(const ArrayHandle& rhs) const - { - return (this->Internals == rhs.Internals); - } - - VTKM_CONT - bool operator!=(const ArrayHandle& rhs) const - { - return (this->Internals != rhs.Internals); - } - - template - VTKM_CONT bool operator==(const ArrayHandle&) const - { - return false; // different valuetype and/or storage - } - - template - VTKM_CONT bool operator!=(const ArrayHandle&) const - { - return true; // different valuetype and/or storage - } - - /// Get the storage. - /// - VTKM_CONT StorageType& GetStorage(); - - /// Get the storage. - /// - VTKM_CONT const StorageType& GetStorage() const; - - /// Get the array portal of the control array. - /// Since worklet invocations are asynchronous and this routine is a synchronization point, - /// exceptions maybe thrown for errors from previously executed worklets. - /// - /// \deprecated Use `WritePortal` instead. Note that the portal returned from `WritePortal` - /// will disallow any other reads or writes to the array while it is in scope. - /// - VTKM_CONT - VTKM_DEPRECATED(1.6, - "Use ArrayHandle::WritePortal() instead. " - "Note that the returned portal will lock the array while it is in scope.") - - /// \cond NOPE - typename StorageType::PortalType GetPortalControl(); - /// \endcond - - /// Get the array portal of the control array. - /// Since worklet invocations are asynchronous and this routine is a synchronization point, - /// exceptions maybe thrown for errors from previously executed worklets. - /// - /// \deprecated Use `ReadPortal` instead. Note that the portal returned from `ReadPortal` - /// will disallow any writes to the array while it is in scope. - /// - VTKM_CONT - VTKM_DEPRECATED(1.6, - "Use ArrayHandle::ReadPortal() instead. " - "Note that the returned portal will lock the array while it is in scope.") - /// \cond NOPE - typename StorageType::PortalConstType GetPortalConstControl() const; - /// \endcond - - /// \@{ - /// \brief Get an array portal that can be used in the control environment. - /// - /// The returned array can be used in the control environment to read values from the array. (It - /// is not possible to write to the returned portal. That is `Get` will work on the portal, but - /// `Set` will not.) - /// - /// **Note:** The returned portal cannot be used in the execution environment. This is because - /// the portal will not work on some devices like GPUs. To get a portal that will work in the - /// execution environment, use `PrepareForInput`. - /// - VTKM_CONT ReadPortalType ReadPortal() const; - /// \@} - - /// \@{ - /// \brief Get an array portal that can be used in the control environment. - /// - /// The returned array can be used in the control environment to reand and write values to the - /// array. - /// - /// - /// **Note:** The returned portal cannot be used in the execution environment. This is because - /// the portal will not work on some devices like GPUs. To get a portal that will work in the - /// execution environment, use `PrepareForInput`. - /// - VTKM_CONT WritePortalType WritePortal() const; - /// \@} - - /// Returns the number of entries in the array. - /// - VTKM_CONT vtkm::Id GetNumberOfValues() const - { - LockType lock = this->GetLock(); - - return this->GetNumberOfValues(lock); - } - - /// \brief Allocates an array large enough to hold the given number of values. - /// - /// The allocation may be done on an already existing array, but can wipe out - /// any data already in the array. This method can throw - /// ErrorBadAllocation if the array cannot be allocated or - /// ErrorBadValue if the allocation is not feasible (for example, the - /// array storage is read-only). - /// - VTKM_CONT - void Allocate(vtkm::Id numberOfValues) - { - vtkm::cont::Token token; - this->Allocate(numberOfValues, token); - } - VTKM_CONT void Allocate(vtkm::Id numberOfValues, vtkm::cont::Token& token) - { - LockType lock = this->GetLock(); - this->WaitToWrite(lock, token); - this->ReleaseResourcesExecutionInternal(lock, token); - this->Internals->GetControlArray(lock)->Allocate(numberOfValues); - // Set to false and then to true to ensure anything pointing to an array before the allocate - // is invalidated. - this->Internals->SetControlArrayValid(lock, false); - this->Internals->SetControlArrayValid(lock, true); - } - - /// \brief Reduces the size of the array without changing its values. - /// - /// This method allows you to resize the array without reallocating it. The - /// number of entries in the array is changed to \c numberOfValues. The data - /// in the array (from indices 0 to \c numberOfValues - 1) are the same, but - /// \c numberOfValues must be equal or less than the preexisting size - /// (returned from GetNumberOfValues). That is, this method can only be used - /// to shorten the array, not lengthen. - VTKM_CONT void Shrink(vtkm::Id numberOfValues) - { - vtkm::cont::Token token; - this->Shrink(numberOfValues, token); - } - VTKM_CONT void Shrink(vtkm::Id numberOfValues, vtkm::cont::Token& token); - - /// Releases any resources being used in the execution environment (that are - /// not being shared by the control environment). - /// - VTKM_CONT void ReleaseResourcesExecution() - { - // A Token should not be declared within the scope of a lock. when the token goes out of scope - // it will attempt to aquire the lock, which is undefined behavior of the thread already has - // the lock. - vtkm::cont::Token token; - { - LockType lock = this->GetLock(); - this->WaitToWrite(lock, token); - - // Save any data in the execution environment by making sure it is synced - // with the control environment. - this->SyncControlArray(lock, token); - - this->ReleaseResourcesExecutionInternal(lock, token); - } - } - - /// Releases all resources in both the control and execution environments. - /// - VTKM_CONT void ReleaseResources() - { - // A Token should not be declared within the scope of a lock. when the token goes out of scope - // it will attempt to aquire the lock, which is undefined behavior of the thread already has - // the lock. - vtkm::cont::Token token; - { - LockType lock = this->GetLock(); - - this->ReleaseResourcesExecutionInternal(lock, token); - - if (this->Internals->IsControlArrayValid(lock)) - { - this->Internals->GetControlArray(lock)->ReleaseResources(); - this->Internals->SetControlArrayValid(lock, false); - } - } - } - - /// Prepares this array to be used as an input to an operation in the - /// execution environment. If necessary, copies data to the execution - /// environment. Can throw an exception if this array does not yet contain - /// any data. Returns a portal that can be used in code running in the - /// execution environment. - /// - /// The `Token` object provided will be attached to this `ArrayHandle`. - /// The returned portal is guaranteed to be valid while the `Token` is - /// still attached and in scope. Other operations on this `ArrayHandle` - /// that would invalidate the returned portal will block until the `Token` - /// is released. Likewise, this method will block if another `Token` is - /// already attached. This can potentially lead to deadlocks. - /// - template - VTKM_CONT typename ExecutionTypes::PortalConst PrepareForInput( - DeviceAdapterTag, - vtkm::cont::Token& token) const; - - /// Prepares (allocates) this array to be used as an output from an operation - /// in the execution environment. The internal state of this class is set to - /// have valid data in the execution array with the assumption that the array - /// will be filled soon (i.e. before any other methods of this object are - /// called). Returns a portal that can be used in code running in the - /// execution environment. - /// - /// The `Token` object provided will be attached to this `ArrayHandle`. - /// The returned portal is guaranteed to be valid while the `Token` is - /// still attached and in scope. Other operations on this `ArrayHandle` - /// that would invalidate the returned portal will block until the `Token` - /// is released. Likewise, this method will block if another `Token` is - /// already attached. This can potentially lead to deadlocks. - /// - template - VTKM_CONT typename ExecutionTypes::Portal - PrepareForOutput(vtkm::Id numberOfValues, DeviceAdapterTag, vtkm::cont::Token& token); - - /// Prepares this array to be used in an in-place operation (both as input - /// and output) in the execution environment. If necessary, copies data to - /// the execution environment. Can throw an exception if this array does not - /// yet contain any data. Returns a portal that can be used in code running - /// in the execution environment. - /// - /// The `Token` object provided will be attached to this `ArrayHandle`. - /// The returned portal is guaranteed to be valid while the `Token` is - /// still attached and in scope. Other operations on this `ArrayHandle` - /// that would invalidate the returned portal will block until the `Token` - /// is released. Likewise, this method will block if another `Token` is - /// already attached. This can potentially lead to deadlocks. - /// - template - VTKM_CONT typename ExecutionTypes::Portal PrepareForInPlace( - DeviceAdapterTag, - vtkm::cont::Token& token); - - template - VTKM_CONT VTKM_DEPRECATED(1.6, "PrepareForInput now requires a vtkm::cont::Token object.") - typename ExecutionTypes::PortalConst PrepareForInput(DeviceAdapterTag) const - { - vtkm::cont::Token token; - return this->PrepareForInput(DeviceAdapterTag{}, token); - } - template - VTKM_CONT VTKM_DEPRECATED(1.6, "PrepareForOutput now requires a vtkm::cont::Token object.") - typename ExecutionTypes::Portal - PrepareForOutput(vtkm::Id numberOfValues, DeviceAdapterTag) - { - vtkm::cont::Token token; - return this->PrepareForOutput(numberOfValues, DeviceAdapterTag{}, token); - } - template - VTKM_CONT VTKM_DEPRECATED(1.6, "PrepareForInPlace now requires a vtkm::cont::Token object.") - typename ExecutionTypes::Portal PrepareForInPlace(DeviceAdapterTag) - { - vtkm::cont::Token token; - return this->PrepareForInPlace(DeviceAdapterTag{}, token); - } - - /// Returns the DeviceAdapterId for the current device. If there is no device - /// with an up-to-date copy of the data, VTKM_DEVICE_ADAPTER_UNDEFINED is - /// returned. - /// - /// Note that in a multithreaded environment the validity of this result can - /// change. - VTKM_CONT - DeviceAdapterId GetDeviceAdapterId() const - { - LockType lock = this->GetLock(); - return this->Internals->IsExecutionArrayValid(lock) - ? this->Internals->GetExecutionArray(lock)->GetDeviceAdapterId() - : DeviceAdapterTagUndefined{}; - } - - /// Synchronizes the control array with the execution array. If either the - /// user array or control array is already valid, this method does nothing - /// (because the data is already available in the control environment). - /// Although the internal state of this class can change, the method is - /// declared const because logically the data does not. - /// - VTKM_CONT void SyncControlArray() const - { - // A Token should not be declared within the scope of a lock. when the token goes out of scope - // it will attempt to aquire the lock, which is undefined behavior of the thread already has - // the lock. - vtkm::cont::Token token; - { - LockType lock = this->GetLock(); - this->SyncControlArray(lock, token); - } - } - - /// \brief Enqueue a token for access to this ArrayHandle. - /// - /// This method places the given `Token` into the queue of `Token`s waiting for - /// access to this `ArrayHandle` and then returns immediately. When this token - /// is later used to get data from this `ArrayHandle` (for example, in a call to - /// `PrepareForInput`), it will use this place in the queue while waiting for - /// access. - /// - /// This method is to be used to ensure that a set of accesses to an `ArrayHandle` - /// that happen on multiple threads occur in a specified order. For example, if - /// you spawn of a job to modify data in an `ArrayHandle` and then spawn off a job - /// that reads that same data, you need to make sure that the first job gets - /// access to the `ArrayHandle` before the second. If they both just attempt to call - /// their respective `Prepare` methods, there is no guarantee which order they - /// will occur. Having the spawning thread first call this method will ensure the order. - /// - /// \warning After calling this method it is required to subsequently - /// call a method like one of the `Prepare` methods that attaches the token - /// to this `ArrayHandle`. Otherwise, the enqueued token will block any subsequent - /// access to the `ArrayHandle`, even if the `Token` is destroyed. - /// - VTKM_CONT void Enqueue(const vtkm::cont::Token& token) const; - -private: - /// Acquires a lock on the internals of this `ArrayHandle`. The calling - /// function should keep the returned lock and let it go out of scope - /// when the lock is no longer needed. - /// - LockType GetLock() const { return LockType(this->Internals->Mutex); } - - /// Returns true if read operations can currently be performed. - /// - VTKM_CONT bool CanRead(const LockType& lock, const vtkm::cont::Token& token) const; - - //// Returns true if write operations can currently be performed. - /// - VTKM_CONT bool CanWrite(const LockType& lock, const vtkm::cont::Token& token) const; - - //// Will block the current thread until a read can be performed. - /// - VTKM_CONT void WaitToRead(LockType& lock, vtkm::cont::Token& token) const; - - //// Will block the current thread until a write can be performed. - /// - VTKM_CONT void WaitToWrite(LockType& lock, vtkm::cont::Token& token, bool fakeRead = false) const; - - /// Gets this array handle ready to interact with the given device. If the - /// array handle has already interacted with this device, then this method - /// does nothing. Although the internal state of this class can change, the - /// method is declared const because logically the data does not. - /// - template - VTKM_CONT void PrepareForDevice(LockType& lock, vtkm::cont::Token& token, DeviceAdapterTag) const; - - /// Synchronizes the control array with the execution array. If either the - /// user array or control array is already valid, this method does nothing - /// (because the data is already available in the control environment). - /// Although the internal state of this class can change, the method is - /// declared const because logically the data does not. - /// - VTKM_CONT void SyncControlArray(LockType& lock, vtkm::cont::Token& token) const; - - vtkm::Id GetNumberOfValues(LockType& lock) const; - - VTKM_CONT - void ReleaseResourcesExecutionInternal(LockType& lock, vtkm::cont::Token& token) const - { - if (this->Internals->IsExecutionArrayValid(lock)) - { - this->WaitToWrite(lock, token); - // Note that it is possible that while waiting someone else deleted the execution array. - // That is why we check again. - } - if (this->Internals->IsExecutionArrayValid(lock)) - { - this->Internals->GetExecutionArray(lock)->ReleaseResources(); - this->Internals->SetExecutionArrayValid(lock, false); - } - } - - VTKM_CONT void Enqueue(const LockType& lock, const vtkm::cont::Token& token) const; - - class VTKM_ALWAYS_EXPORT InternalStruct - { - mutable StorageType ControlArray; - mutable std::shared_ptr ControlArrayValid; - - mutable std::unique_ptr ExecutionArray; - mutable bool ExecutionArrayValid = false; - - mutable vtkm::cont::Token::ReferenceCount ReadCount = 0; - mutable vtkm::cont::Token::ReferenceCount WriteCount = 0; - - mutable std::deque Queue; - - VTKM_CONT void CheckLock(const LockType& lock) const - { - VTKM_ASSERT((lock.mutex() == &this->Mutex) && (lock.owns_lock())); - } - - public: - MutexType Mutex; - std::condition_variable ConditionVariable; - - InternalStruct() = default; - InternalStruct(const StorageType& storage); - InternalStruct(StorageType&& storage); - - ~InternalStruct() - { - // It should not be possible to destroy this array if any tokens are still attached to it. - LockType lock(this->Mutex); - VTKM_ASSERT((*this->GetReadCount(lock) == 0) && (*this->GetWriteCount(lock) == 0)); - this->SetControlArrayValid(lock, false); - } - - // To access any feature in InternalStruct, you must have locked the mutex. You have - // to prove it by passing in a reference to a std::unique_lock. - VTKM_CONT bool IsControlArrayValid(const LockType& lock) const - { - this->CheckLock(lock); - if (!this->ControlArrayValid) - { - return false; - } - else - { - return *this->ControlArrayValid; - } - } - VTKM_CONT void SetControlArrayValid(const LockType& lock, bool value) - { - this->CheckLock(lock); - if (IsControlArrayValid(lock) == value) - { - return; - } - if (value) // ControlArrayValid == false or nullptr - { - // If we are changing the valid flag from false to true, then refresh the pointer. - // There may be array portals that already have a reference to the flag. Those portals - // will stay in an invalid state whereas new portals will go to a valid state. To - // handle both conditions, drop the old reference and create a new one. - this->ControlArrayValid.reset(new bool(true)); - } - else // value == false and ControlArrayValid == true - { - *this->ControlArrayValid = false; - } - } - VTKM_CONT std::shared_ptr GetControlArrayValidPointer(const LockType& lock) const - { - this->CheckLock(lock); - return this->ControlArrayValid; - } - VTKM_CONT StorageType* GetControlArray(const LockType& lock) const - { - this->CheckLock(lock); - return &this->ControlArray; - } - - VTKM_CONT bool IsExecutionArrayValid(const LockType& lock) const - { - this->CheckLock(lock); - return this->ExecutionArrayValid; - } - VTKM_CONT void SetExecutionArrayValid(const LockType& lock, bool value) - { - this->CheckLock(lock); - this->ExecutionArrayValid = value; - } - VTKM_CONT ExecutionManagerType* GetExecutionArray(const LockType& lock) const - { - this->CheckLock(lock); - return this->ExecutionArray.get(); - } - VTKM_CONT void DeleteExecutionArray(const LockType& lock) - { - this->CheckLock(lock); - this->ExecutionArray.reset(); - this->ExecutionArrayValid = false; - } - template - VTKM_CONT void NewExecutionArray(const LockType& lock, DeviceAdapterTag) - { - VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapterTag); - this->CheckLock(lock); - VTKM_ASSERT(this->ExecutionArray == nullptr); - VTKM_ASSERT(!this->ExecutionArrayValid); - this->ExecutionArray.reset( - new vtkm::cont::internal::ArrayHandleExecutionManager( - &this->ControlArray)); - } - VTKM_CONT vtkm::cont::Token::ReferenceCount* GetReadCount(const LockType& lock) const - { - this->CheckLock(lock); - return &this->ReadCount; - } - VTKM_CONT vtkm::cont::Token::ReferenceCount* GetWriteCount(const LockType& lock) const - { - this->CheckLock(lock); - return &this->WriteCount; - } - VTKM_CONT std::deque& GetQueue(const LockType& lock) const - { - this->CheckLock(lock); - return this->Queue; - } - }; - - VTKM_CONT - ArrayHandle(const std::shared_ptr& i) - : Internals(i) - { - } - - std::shared_ptr Internals; -}; - namespace detail { @@ -917,90 +267,26 @@ VTKM_CONT_EXPORT VTKM_CONT vtkm::cont::DeviceAdapterId ArrayHandleGetDeviceAdapt } // namespace detail -// This macro is used to declare an ArrayHandle that uses the new style of Storage -// that leverages Buffer objects. This macro will go away once ArrayHandle -// is replaced with ArrayHandleNewStyle. To use this macro, first have a declaration -// of the template and then put the macro like this: -// -// template -// VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagFoo); -// -// Don't forget to use VTKM_PASS_COMMAS if one of the macro arguments contains -// a template with multiple parameters. -#define VTKM_ARRAY_HANDLE_NEW_STYLE(ValueType_, StorageType_) \ - class VTKM_ALWAYS_EXPORT ArrayHandle \ - : public ArrayHandleNewStyle \ - { \ - using Superclass = ArrayHandleNewStyle; \ - \ - public: \ - VTKM_CONT \ - ArrayHandle() \ - : Superclass() \ - { \ - } \ - \ - VTKM_CONT \ - ArrayHandle(const ArrayHandle& src) \ - : Superclass(src) \ - { \ - } \ - \ - VTKM_CONT \ - ArrayHandle(ArrayHandle&& src) noexcept \ - : Superclass(std::move(src)) \ - { \ - } \ - \ - VTKM_CONT \ - ArrayHandle(const ArrayHandleNewStyle& src) \ - : Superclass(src) \ - { \ - } \ - \ - VTKM_CONT \ - ArrayHandle(ArrayHandleNewStyle&& src) noexcept \ - : Superclass(std::move(src)) \ - { \ - } \ - \ - VTKM_CONT ArrayHandle(const vtkm::cont::internal::Buffer* buffers) \ - : Superclass(buffers) \ - { \ - } \ - \ - VTKM_CONT ArrayHandle(const std::vector& buffers) \ - : Superclass(buffers) \ - { \ - } \ - \ - VTKM_CONT ArrayHandle(std::vector&& buffers) \ - : Superclass(std::move(buffers)) \ - { \ - } \ - \ - VTKM_CONT \ - ArrayHandle& operator=( \ - const ArrayHandle& src) \ - { \ - this->Superclass::operator=(src); \ - return *this; \ - } \ - \ - VTKM_CONT \ - ArrayHandle& operator=( \ - ArrayHandle&& src) noexcept \ - { \ - this->Superclass::operator=(std::move(src)); \ - return *this; \ - } \ - \ - VTKM_CONT ~ArrayHandle() {} \ - } - -/// This new style of ArrayHandle will eventually replace the classic ArrayHandle +/// \brief Manages an array-worth of data. +/// +/// `ArrayHandle` manages as array of data that can be manipulated by VTKm +/// algorithms. The `ArrayHandle` may have up to two copies of the array, one +/// for the control environment and one for the execution environment, although +/// depending on the device and how the array is being used, the `ArrayHandle` +/// will only have one copy when possible. +/// +/// An `ArrayHandle` is often constructed by instantiating one of the `ArrayHandle` +/// subclasses. Several basic `ArrayHandle` types can also be constructed directly +/// and then allocated. The `ArrayHandleBasic` subclass provides mechanisms for +/// importing user arrays into an `ArrayHandle`. +/// +/// `ArrayHandle` behaves like a shared smart pointer in that when it is copied +/// each copy holds a reference to the same array. These copies are reference +/// counted so that when all copies of the `ArrayHandle` are destroyed, any +/// allocated memory is released. +/// template -class VTKM_ALWAYS_EXPORT ArrayHandleNewStyle : public internal::ArrayHandleBase +class VTKM_ALWAYS_EXPORT ArrayHandle : public internal::ArrayHandleBase { public: using ValueType = T; @@ -1025,7 +311,7 @@ public: /// Constructs an empty ArrayHandle. /// - VTKM_CONT ArrayHandleNewStyle() + VTKM_CONT ArrayHandle() : Buffers(static_cast(StorageType::GetNumberOfBuffers())) { } @@ -1037,7 +323,7 @@ public: /// with CUDA), then the automatically generated copy constructor could be /// created for all devices, and it would not be valid for all devices. /// - VTKM_CONT ArrayHandleNewStyle(const vtkm::cont::ArrayHandleNewStyle& src) + VTKM_CONT ArrayHandle(const vtkm::cont::ArrayHandle& src) : Buffers(src.Buffers) { } @@ -1049,8 +335,7 @@ public: /// with CUDA), then the automatically generated move constructor could be /// created for all devices, and it would not be valid for all devices. /// - VTKM_CONT ArrayHandleNewStyle( - vtkm::cont::ArrayHandleNewStyle&& src) noexcept + VTKM_CONT ArrayHandle(vtkm::cont::ArrayHandle&& src) noexcept : Buffers(std::move(src.Buffers)) { } @@ -1059,19 +344,19 @@ public: /// Special constructor for subclass specializations that need to set the /// initial state array. Used when pulling data from other sources. /// - VTKM_CONT ArrayHandleNewStyle(const std::vector& buffers) + VTKM_CONT ArrayHandle(const std::vector& buffers) : Buffers(buffers) { VTKM_ASSERT(static_cast(this->Buffers.size()) == this->GetNumberOfBuffers()); } - VTKM_CONT ArrayHandleNewStyle(std::vector&& buffers) noexcept + VTKM_CONT ArrayHandle(std::vector&& buffers) noexcept : Buffers(std::move(buffers)) { VTKM_ASSERT(static_cast(this->Buffers.size()) == this->GetNumberOfBuffers()); } - VTKM_CONT ArrayHandleNewStyle(const vtkm::cont::internal::Buffer* buffers) + VTKM_CONT ArrayHandle(const vtkm::cont::internal::Buffer* buffers) : Buffers(buffers, buffers + StorageType::GetNumberOfBuffers()) { } @@ -1084,13 +369,13 @@ public: /// with CUDA), then the automatically generated destructor could be /// created for all devices, and it would not be valid for all devices. /// - VTKM_CONT ~ArrayHandleNewStyle() {} + VTKM_CONT ~ArrayHandle() {} /// \brief Copies an ArrayHandle /// VTKM_CONT - vtkm::cont::ArrayHandleNewStyle& operator=( - const vtkm::cont::ArrayHandleNewStyle& src) + vtkm::cont::ArrayHandle& operator=( + const vtkm::cont::ArrayHandle& src) { this->Buffers = src.Buffers; return *this; @@ -1099,8 +384,8 @@ public: /// \brief Move and Assignment of an ArrayHandle /// VTKM_CONT - vtkm::cont::ArrayHandleNewStyle& operator=( - vtkm::cont::ArrayHandleNewStyle&& src) noexcept + vtkm::cont::ArrayHandle& operator=( + vtkm::cont::ArrayHandle&& src) noexcept { this->Buffers = std::move(src.Buffers); return *this; @@ -1411,8 +696,7 @@ public: /// /// Takes the data that is in \a source and copies that data into this array. /// - VTKM_CONT void DeepCopyFrom( - const vtkm::cont::ArrayHandleNewStyle& source) const + VTKM_CONT void DeepCopyFrom(const vtkm::cont::ArrayHandle& source) const { VTKM_ASSERT(this->Buffers.size() == source.Buffers.size()); @@ -1667,8 +951,4 @@ VTKM_CONT inline std::vector CreateBuffers(const A #include #endif -#ifndef vtk_m_cont_ArrayHandle_hxx -#include -#endif - #endif //vtk_m_cont_ArrayHandle_h diff --git a/vtkm/cont/ArrayHandle.hxx b/vtkm/cont/ArrayHandle.hxx deleted file mode 100644 index 33b33b8fe..000000000 --- a/vtkm/cont/ArrayHandle.hxx +++ /dev/null @@ -1,596 +0,0 @@ -//============================================================================ -// 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. -//============================================================================ -#ifndef vtk_m_cont_ArrayHandle_hxx -#define vtk_m_cont_ArrayHandle_hxx - -#include - -namespace vtkm -{ -namespace cont -{ - -template -ArrayHandle::InternalStruct::InternalStruct( - const typename ArrayHandle::StorageType& storage) - : ControlArray(storage) - , ControlArrayValid(new bool(true)) - , ExecutionArrayValid(false) -{ -} - -template -ArrayHandle::InternalStruct::InternalStruct(typename ArrayHandle::StorageType&& storage) - : ControlArray(std::move(storage)) - , ControlArrayValid(new bool(true)) - , ExecutionArrayValid(false) -{ -} - -template -ArrayHandle::ArrayHandle() - : Internals(std::make_shared()) -{ -} - -template -ArrayHandle::ArrayHandle(const ArrayHandle& src) - : Internals(src.Internals) -{ -} - -template -ArrayHandle::ArrayHandle(ArrayHandle&& src) noexcept - : Internals(std::move(src.Internals)) -{ -} - -template -ArrayHandle::ArrayHandle(const typename ArrayHandle::StorageType& storage) - : Internals(std::make_shared(storage)) -{ -} - -template -ArrayHandle::ArrayHandle(typename ArrayHandle::StorageType&& storage) noexcept - : Internals(std::make_shared(std::move(storage))) -{ -} - -template -ArrayHandle::~ArrayHandle() -{ -} - -template -ArrayHandle& ArrayHandle::operator=(const ArrayHandle& src) -{ - this->Internals = src.Internals; - return *this; -} - -template -ArrayHandle& ArrayHandle::operator=(ArrayHandle&& src) noexcept -{ - this->Internals = std::move(src.Internals); - return *this; -} - -template -typename ArrayHandle::StorageType& ArrayHandle::GetStorage() -{ - // A Token should not be declared within the scope of a lock. when the token goes out of scope - // it will attempt to aquire the lock, which is undefined behavior of the thread already has - // the lock. - vtkm::cont::Token token; - { - LockType lock = this->GetLock(); - - this->SyncControlArray(lock, token); - if (this->Internals->IsControlArrayValid(lock)) - { - return *this->Internals->GetControlArray(lock); - } - else - { - throw vtkm::cont::ErrorInternal( - "ArrayHandle::SyncControlArray did not make control array valid."); - } - } -} - -template -const typename ArrayHandle::StorageType& ArrayHandle::GetStorage() const -{ - // A Token should not be declared within the scope of a lock. when the token goes out of scope - // it will attempt to aquire the lock, which is undefined behavior of the thread already has - // the lock. - vtkm::cont::Token token; - { - LockType lock = this->GetLock(); - - this->SyncControlArray(lock, token); - if (this->Internals->IsControlArrayValid(lock)) - { - return *this->Internals->GetControlArray(lock); - } - else - { - throw vtkm::cont::ErrorInternal( - "ArrayHandle::SyncControlArray did not make control array valid."); - } - } -} - -template -typename ArrayHandle::StorageType::PortalType ArrayHandle::GetPortalControl() -{ - // A Token should not be declared within the scope of a lock. when the token goes out of scope - // it will attempt to aquire the lock, which is undefined behavior of the thread already has - // the lock. - vtkm::cont::Token token; - { - LockType lock = this->GetLock(); - - this->SyncControlArray(lock, token); - if (this->Internals->IsControlArrayValid(lock)) - { - // If the user writes into the iterator we return, then the execution - // array will become invalid. Play it safe and release the execution - // resources. (Use the const version to preserve the execution array.) - this->ReleaseResourcesExecutionInternal(lock, token); - return this->Internals->GetControlArray(lock)->GetPortal(); - } - else - { - throw vtkm::cont::ErrorInternal( - "ArrayHandle::SyncControlArray did not make control array valid."); - } - } -} - -template -typename ArrayHandle::StorageType::PortalConstType ArrayHandle::GetPortalConstControl() - const -{ - // A Token should not be declared within the scope of a lock. when the token goes out of scope - // it will attempt to aquire the lock, which is undefined behavior of the thread already has - // the lock. - vtkm::cont::Token token; - { - LockType lock = this->GetLock(); - - this->SyncControlArray(lock, token); - if (this->Internals->IsControlArrayValid(lock)) - { - return this->Internals->GetControlArray(lock)->GetPortalConst(); - } - else - { - throw vtkm::cont::ErrorInternal( - "ArrayHandle::SyncControlArray did not make control array valid."); - } - } -} - -template -typename ArrayHandle::ReadPortalType ArrayHandle::ReadPortal() const -{ - // A Token should not be declared within the scope of a lock. when the token goes out of scope - // it will attempt to aquire the lock, which is undefined behavior of the thread already has - // the lock. - vtkm::cont::Token token; - { - LockType lock = this->GetLock(); - this->WaitToRead(lock, token); - - this->SyncControlArray(lock, token); - if (this->Internals->IsControlArrayValid(lock)) - { - return ReadPortalType(this->Internals->GetControlArray(lock)->GetPortalConst()); - } - else - { - throw vtkm::cont::ErrorInternal( - "ArrayHandle::SyncControlArray did not make control array valid."); - } - } -} - -template -typename ArrayHandle::WritePortalType ArrayHandle::WritePortal() const -{ - // A Token should not be declared within the scope of a lock. when the token goes out of scope - // it will attempt to aquire the lock, which is undefined behavior of the thread already has - // the lock. - vtkm::cont::Token token; - { - LockType lock = this->GetLock(); - this->WaitToWrite(lock, token); - - this->SyncControlArray(lock, token); - if (this->Internals->IsControlArrayValid(lock)) - { - // If the user writes into the iterator we return, then the execution - // array will become invalid. Play it safe and release the execution - // resources. (Use the const version to preserve the execution array.) - this->ReleaseResourcesExecutionInternal(lock, token); - return WritePortalType(this->Internals->GetControlArray(lock)->GetPortal()); - } - else - { - throw vtkm::cont::ErrorInternal( - "ArrayHandle::SyncControlArray did not make control array valid."); - } - } -} - -template -vtkm::Id ArrayHandle::GetNumberOfValues(LockType& lock) const -{ - if (this->Internals->IsControlArrayValid(lock)) - { - return this->Internals->GetControlArray(lock)->GetNumberOfValues(); - } - else if (this->Internals->IsExecutionArrayValid(lock)) - { - return this->Internals->GetExecutionArray(lock)->GetNumberOfValues(); - } - else - { - return 0; - } -} - -template -void ArrayHandle::Shrink(vtkm::Id numberOfValues, vtkm::cont::Token& token) -{ - VTKM_ASSERT(numberOfValues >= 0); - - if (numberOfValues > 0) - { - LockType lock = this->GetLock(); - - vtkm::Id originalNumberOfValues = this->GetNumberOfValues(lock); - - if (numberOfValues < originalNumberOfValues) - { - this->WaitToWrite(lock, token); - if (this->Internals->IsControlArrayValid(lock)) - { - this->Internals->GetControlArray(lock)->Shrink(numberOfValues); - } - if (this->Internals->IsExecutionArrayValid(lock)) - { - this->Internals->GetExecutionArray(lock)->Shrink(numberOfValues); - } - } - else if (numberOfValues == originalNumberOfValues) - { - // Nothing to do. - } - else // numberOfValues > originalNumberOfValues - { - throw vtkm::cont::ErrorBadValue("ArrayHandle::Shrink cannot be used to grow array."); - } - - VTKM_ASSERT(this->GetNumberOfValues(lock) == numberOfValues); - } - else // numberOfValues == 0 - { - // If we are shrinking to 0, there is nothing to save and we might as well - // free up memory. Plus, some storage classes expect that data will be - // deallocated when the size goes to zero. - this->Allocate(0, token); - } -} - -template -template -typename ArrayHandle::template ExecutionTypes::PortalConst -ArrayHandle::PrepareForInput(DeviceAdapterTag device, vtkm::cont::Token& token) const -{ - VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapterTag); - - LockType lock = this->GetLock(); - this->WaitToRead(lock, token); - - if (!this->Internals->IsControlArrayValid(lock) && !this->Internals->IsExecutionArrayValid(lock)) - { - // Want to use an empty array. - // Set up ArrayHandle state so this actually works. - this->Internals->GetControlArray(lock)->Allocate(0); - this->Internals->SetControlArrayValid(lock, true); - } - - this->PrepareForDevice(lock, token, device); - auto portal = this->Internals->GetExecutionArray(lock)->PrepareForInput( - !this->Internals->IsExecutionArrayValid(lock), device, token); - - this->Internals->SetExecutionArrayValid(lock, true); - - return portal; -} - -template -template -typename ArrayHandle::template ExecutionTypes::Portal -ArrayHandle::PrepareForOutput(vtkm::Id numberOfValues, - DeviceAdapterTag device, - vtkm::cont::Token& token) -{ - VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapterTag); - - LockType lock = this->GetLock(); - this->WaitToWrite(lock, token); - - // Invalidate any control arrays. - // Should the control array resource be released? Probably not a good - // idea when shared with execution. - this->Internals->SetControlArrayValid(lock, false); - - this->PrepareForDevice(lock, token, device); - auto portal = - this->Internals->GetExecutionArray(lock)->PrepareForOutput(numberOfValues, device, token); - - // We are assuming that the calling code will fill the array using the - // iterators we are returning, so go ahead and mark the execution array as - // having valid data. (A previous version of this class had a separate call - // to mark the array as filled, but that was onerous to call at the the - // right time and rather pointless since it is basically always the case - // that the array is going to be filled before anything else. In this - // implementation the only access to the array is through the iterators - // returned from this method, so you would have to work to invalidate this - // assumption anyway.) - this->Internals->SetExecutionArrayValid(lock, true); - - return portal; -} - -template -template -typename ArrayHandle::template ExecutionTypes::Portal -ArrayHandle::PrepareForInPlace(DeviceAdapterTag device, vtkm::cont::Token& token) -{ - VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapterTag); - - LockType lock = this->GetLock(); - this->WaitToWrite(lock, token); - - if (!this->Internals->IsControlArrayValid(lock) && !this->Internals->IsExecutionArrayValid(lock)) - { - // Want to use an empty array. - // Set up ArrayHandle state so this actually works. - this->Internals->GetControlArray(lock)->Allocate(0); - this->Internals->SetControlArrayValid(lock, true); - } - - this->PrepareForDevice(lock, token, device); - auto portal = this->Internals->GetExecutionArray(lock)->PrepareForInPlace( - !this->Internals->IsExecutionArrayValid(lock), device, token); - - this->Internals->SetExecutionArrayValid(lock, true); - - // Invalidate any control arrays since their data will become invalid when - // the execution data is overwritten. Don't actually release the control - // array. It may be shared as the execution array. - this->Internals->SetControlArrayValid(lock, false); - - return portal; -} - -template -template -void ArrayHandle::PrepareForDevice(LockType& lock, - vtkm::cont::Token& token, - DeviceAdapterTag device) const -{ - if (this->Internals->GetExecutionArray(lock) != nullptr) - { - if (this->Internals->GetExecutionArray(lock)->IsDeviceAdapter(DeviceAdapterTag())) - { - // Already have manager for correct device adapter. Nothing to do. - return; - } - else - { - // Have the wrong manager. Delete the old one and create a new one - // of the right type. (TODO: it would be possible for the array handle - // to hold references to execution arrays on multiple devices. When data - // are written on one devices, all the other devices should get cleared.) - - // BUG: There is a non-zero chance that while waiting for the write lock, another thread - // could change the ExecutionInterface, which would cause problems. In the future we should - // support multiple devices, in which case we would not have to delete one execution array - // to load another. - // BUG: The current implementation does not allow the ArrayHandle to be on two devices - // at the same time. Thus, it is not possible for two simultaneously read from the same - // ArrayHandle on two different devices. This might cause unexpected deadlocks. - this->WaitToWrite(lock, token, true); // Make sure no one is reading device array - this->SyncControlArray(lock, token); - // Need to change some state that does not change the logical state from - // an external point of view. - this->Internals->DeleteExecutionArray(lock); - } - } - - // Need to change some state that does not change the logical state from - // an external point of view. - this->Internals->NewExecutionArray(lock, device); -} - -template -void ArrayHandle::SyncControlArray(LockType& lock, vtkm::cont::Token& token) const -{ - if (!this->Internals->IsControlArrayValid(lock)) - { - // It may be the case that `SyncControlArray` is called from a method that has a `Token`. - // However, if we are here, that `Token` should not already be attached to this array. - // If it were, then there should be no reason to move data arround (unless the `Token` - // was used when preparing for multiple devices, which it should not be used like that). - this->WaitToRead(lock, token); - - // Need to change some state that does not change the logical state from - // an external point of view. - if (this->Internals->IsExecutionArrayValid(lock)) - { - this->Internals->GetExecutionArray(lock)->RetrieveOutputData( - this->Internals->GetControlArray(lock)); - this->Internals->SetControlArrayValid(lock, true); - } - else - { - // This array is in the null state (there is nothing allocated), but - // the calling function wants to do something with the array. Put this - // class into a valid state by allocating an array of size 0. - this->Internals->GetControlArray(lock)->Allocate(0); - this->Internals->SetControlArrayValid(lock, true); - } - } -} - -template -bool ArrayHandle::CanRead(const LockType& lock, const vtkm::cont::Token& token) const -{ - // If the token is already attached to this array, then we allow reading. - if (token.IsAttached(this->Internals->GetWriteCount(lock)) || - token.IsAttached(this->Internals->GetReadCount(lock))) - { - return true; - } - - // If there is anyone else waiting at the top of the queue, we cannot access this array. - auto& queue = this->Internals->GetQueue(lock); - if (!queue.empty() && (queue.front() != token)) - { - return false; - } - - // No one else is waiting, so we can read the array as long as no one else is writing. - return (*this->Internals->GetWriteCount(lock) < 1); -} - -template -bool ArrayHandle::CanWrite(const LockType& lock, const vtkm::cont::Token& token) const -{ - // If the token is already attached to this array, then we allow writing. - if (token.IsAttached(this->Internals->GetWriteCount(lock)) || - token.IsAttached(this->Internals->GetReadCount(lock))) - { - return true; - } - - // If there is anyone else waiting at the top of the queue, we cannot access this array. - auto& queue = this->Internals->GetQueue(lock); - if (!queue.empty() && (queue.front() != token)) - { - return false; - } - - // No one else is waiting, so we can write the array as long as no one else is reading or writing. - return ((*this->Internals->GetWriteCount(lock) < 1) && - (*this->Internals->GetReadCount(lock) < 1)); -} - -template -void ArrayHandle::WaitToRead(LockType& lock, vtkm::cont::Token& token) const -{ - this->Enqueue(lock, token); - - // Note that if you deadlocked here, that means that you are trying to do a read operation on an - // array where an object is writing to it. - this->Internals->ConditionVariable.wait( - lock, [&lock, &token, this] { return this->CanRead(lock, token); }); - - token.Attach(this->Internals, - this->Internals->GetReadCount(lock), - lock, - &this->Internals->ConditionVariable); - - // We successfully attached the token. Pop it off the queue. - auto& queue = this->Internals->GetQueue(lock); - if (!queue.empty() && queue.front() == token) - { - queue.pop_front(); - } -} - -template -void ArrayHandle::WaitToWrite(LockType& lock, vtkm::cont::Token& token, bool fakeRead) const -{ - this->Enqueue(lock, token); - - // Note that if you deadlocked here, that means that you are trying to do a write operation on an - // array where an object is reading or writing to it. - this->Internals->ConditionVariable.wait( - lock, [&lock, &token, this] { return this->CanWrite(lock, token); }); - - if (!fakeRead) - { - token.Attach(this->Internals, - this->Internals->GetWriteCount(lock), - lock, - &this->Internals->ConditionVariable); - } - else - { - // A current feature limitation of ArrayHandle is that it can only exist on one device at - // a time. Thus, if a read request comes in for a different device, the prepare has to - // get satisfy a write lock to boot the array off the existing device. However, we don't - // want to attach the Token as a write lock because the resulting state is for reading only - // and others might also want to read. So, we have to pretend that this is a read lock even - // though we have to make a change to the array. - // - // The main point is, this condition is a hack that should go away once ArrayHandle supports - // multiple devices at once. - token.Attach(this->Internals, - this->Internals->GetReadCount(lock), - lock, - &this->Internals->ConditionVariable); - } - - // We successfully attached the token. Pop it off the queue. - auto& queue = this->Internals->GetQueue(lock); - if (!queue.empty() && queue.front() == token) - { - queue.pop_front(); - } -} - -template -void ArrayHandle::Enqueue(const vtkm::cont::Token& token) const -{ - LockType lock = this->GetLock(); - this->Enqueue(lock, token); -} - -template -void ArrayHandle::Enqueue(const LockType& lock, const vtkm::cont::Token& token) const -{ - if (token.IsAttached(this->Internals->GetWriteCount(lock)) || - token.IsAttached(this->Internals->GetReadCount(lock))) - { - // Do not need to enqueue if we are already attached. - return; - } - - auto& queue = this->Internals->GetQueue(lock); - if (std::find(queue.begin(), queue.end(), token.GetReference()) != queue.end()) - { - // This token is already in the queue. - return; - } - - this->Internals->GetQueue(lock).push_back(token.GetReference()); -} -} -} // vtkm::cont - -#endif //vtk_m_cont_ArrayHandle_hxx diff --git a/vtkm/cont/ArrayHandleBasic.cxx b/vtkm/cont/ArrayHandleBasic.cxx index b6d52d745..bb0209edb 100644 --- a/vtkm/cont/ArrayHandleBasic.cxx +++ b/vtkm/cont/ArrayHandleBasic.cxx @@ -41,11 +41,11 @@ VTKM_STORAGE_INSTANTIATE(vtkm::Float64) } // namespace internal -#define VTKM_ARRAYHANDLE_INSTANTIATE(Type) \ - template class VTKM_CONT_EXPORT ArrayHandleNewStyle; \ - template class VTKM_CONT_EXPORT ArrayHandleNewStyle, StorageTagBasic>; \ - template class VTKM_CONT_EXPORT ArrayHandleNewStyle, StorageTagBasic>; \ - template class VTKM_CONT_EXPORT ArrayHandleNewStyle, StorageTagBasic>; +#define VTKM_ARRAYHANDLE_INSTANTIATE(Type) \ + template class VTKM_CONT_EXPORT ArrayHandle; \ + template class VTKM_CONT_EXPORT ArrayHandle, StorageTagBasic>; \ + template class VTKM_CONT_EXPORT ArrayHandle, StorageTagBasic>; \ + template class VTKM_CONT_EXPORT ArrayHandle, StorageTagBasic>; VTKM_ARRAYHANDLE_INSTANTIATE(char) VTKM_ARRAYHANDLE_INSTANTIATE(vtkm::Int8) diff --git a/vtkm/cont/ArrayHandleBasic.h b/vtkm/cont/ArrayHandleBasic.h index 57395793c..7ce67c771 100644 --- a/vtkm/cont/ArrayHandleBasic.h +++ b/vtkm/cont/ArrayHandleBasic.h @@ -11,6 +11,7 @@ #define vtk_m_cont_ArrayHandleBasic_h #include +#include #include #include #include @@ -70,9 +71,6 @@ public: } // namespace internal -template -VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagBasic); - template class VTKM_ALWAYS_EXPORT ArrayHandleBasic : public ArrayHandle { @@ -383,14 +381,13 @@ VTKM_STORAGE_EXPORT(vtkm::Float64) } // namespace internal -#define VTKM_ARRAYHANDLE_EXPORT(Type) \ - extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleNewStyle; \ - extern template class VTKM_CONT_TEMPLATE_EXPORT \ - ArrayHandleNewStyle, StorageTagBasic>; \ - extern template class VTKM_CONT_TEMPLATE_EXPORT \ - ArrayHandleNewStyle, StorageTagBasic>; \ - extern template class VTKM_CONT_TEMPLATE_EXPORT \ - ArrayHandleNewStyle, StorageTagBasic>; +#define VTKM_ARRAYHANDLE_EXPORT(Type) \ + extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle; \ + extern template class VTKM_CONT_TEMPLATE_EXPORT \ + ArrayHandle, StorageTagBasic>; \ + extern template class VTKM_CONT_TEMPLATE_EXPORT \ + ArrayHandle, StorageTagBasic>; \ + extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle, StorageTagBasic>; VTKM_ARRAYHANDLE_EXPORT(char) VTKM_ARRAYHANDLE_EXPORT(vtkm::Int8) diff --git a/vtkm/cont/ArrayHandleBitField.h b/vtkm/cont/ArrayHandleBitField.h index 4a0b47541..870efae9e 100644 --- a/vtkm/cont/ArrayHandleBitField.h +++ b/vtkm/cont/ArrayHandleBitField.h @@ -136,9 +136,6 @@ public: } // end namespace internal -template -VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::internal::StorageTagBitField); - /// The ArrayHandleBitField class is a boolean-valued ArrayHandle that is backed /// by a BitField. /// diff --git a/vtkm/cont/ArrayHandleCartesianProduct.h b/vtkm/cont/ArrayHandleCartesianProduct.h index f6491e6ed..aabd06312 100644 --- a/vtkm/cont/ArrayHandleCartesianProduct.h +++ b/vtkm/cont/ArrayHandleCartesianProduct.h @@ -284,11 +284,6 @@ public: }; } // namespace internal -template -VTKM_ARRAY_HANDLE_NEW_STYLE( - T, - VTKM_PASS_COMMAS(vtkm::cont::StorageTagCartesianProduct)); - /// ArrayHandleCartesianProduct is a specialization of ArrayHandle. It takes two delegate /// array handle and makes a new handle that access the corresponding entries /// in these arrays as a pair. diff --git a/vtkm/cont/ArrayHandleCast.h b/vtkm/cont/ArrayHandleCast.h index 140dcc7a9..84c95cdb3 100644 --- a/vtkm/cont/ArrayHandleCast.h +++ b/vtkm/cont/ArrayHandleCast.h @@ -131,9 +131,6 @@ struct Storage> } // namespace internal -template -VTKM_ARRAY_HANDLE_NEW_STYLE(T1, VTKM_PASS_COMMAS(vtkm::cont::StorageTagCast)); - /// \brief Cast the values of an array to the specified type, on demand. /// /// ArrayHandleCast is a specialization of ArrayHandleTransform. Given an ArrayHandle diff --git a/vtkm/cont/ArrayHandleCompositeVector.h b/vtkm/cont/ArrayHandleCompositeVector.h index 66e1920a5..d93838d3f 100644 --- a/vtkm/cont/ArrayHandleCompositeVector.h +++ b/vtkm/cont/ArrayHandleCompositeVector.h @@ -402,9 +402,6 @@ struct Storage> : Storage -VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagCompositeVec); - /// \brief An \c ArrayHandle that combines components from other arrays. /// /// \c ArrayHandleCompositeVector is a specialization of \c ArrayHandle that diff --git a/vtkm/cont/ArrayHandleConcatenate.h b/vtkm/cont/ArrayHandleConcatenate.h index b860d1243..fd1a0a582 100644 --- a/vtkm/cont/ArrayHandleConcatenate.h +++ b/vtkm/cont/ArrayHandleConcatenate.h @@ -245,9 +245,6 @@ namespace vtkm namespace cont { -template -VTKM_ARRAY_HANDLE_NEW_STYLE(T, VTKM_PASS_COMMAS(StorageTagConcatenate)); - template class ArrayHandleConcatenate : public vtkm::cont::ArrayHandle : Storage -VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagConstant); - /// \brief An array handle with a constant value. /// /// ArrayHandleConstant is an implicit array handle with a constant value. A diff --git a/vtkm/cont/ArrayHandleCounting.h b/vtkm/cont/ArrayHandleCounting.h index 01658e386..cab304563 100644 --- a/vtkm/cont/ArrayHandleCounting.h +++ b/vtkm/cont/ArrayHandleCounting.h @@ -83,9 +83,6 @@ struct Storage : Storage -VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagCounting); - /// ArrayHandleCounting is a specialization of ArrayHandle. By default it /// contains a increment value, that is increment for each step between zero /// and the passed in length diff --git a/vtkm/cont/ArrayHandleDecorator.h b/vtkm/cont/ArrayHandleDecorator.h index 1cfd1822d..24f3af9ef 100644 --- a/vtkm/cont/ArrayHandleDecorator.h +++ b/vtkm/cont/ArrayHandleDecorator.h @@ -590,11 +590,6 @@ struct DecoratorHandleTraits } // namespace internal -template -VTKM_ARRAY_HANDLE_NEW_STYLE( - T, - VTKM_PASS_COMMAS(internal::StorageTagDecorator)); - /// \brief A fancy ArrayHandle that can be used to modify the results from one /// or more source ArrayHandle. /// diff --git a/vtkm/cont/ArrayHandleDiscard.h b/vtkm/cont/ArrayHandleDiscard.h index 0c331e655..953f4fdc1 100644 --- a/vtkm/cont/ArrayHandleDiscard.h +++ b/vtkm/cont/ArrayHandleDiscard.h @@ -144,10 +144,6 @@ struct ArrayHandleDiscardTraits } // end namespace internal -// This can go away once ArrayHandle is replaced with ArrayHandleNewStyle -template -VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::internal::StorageTagDiscard); - /// ArrayHandleDiscard is a write-only array that discards all data written to /// it. This can be used to save memory when a filter provides optional outputs /// that are not needed. diff --git a/vtkm/cont/ArrayHandleExtractComponent.h b/vtkm/cont/ArrayHandleExtractComponent.h index 70926932b..6bf270ad1 100644 --- a/vtkm/cont/ArrayHandleExtractComponent.h +++ b/vtkm/cont/ArrayHandleExtractComponent.h @@ -170,9 +170,6 @@ namespace vtkm namespace cont { -template -VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagExtractComponent); - /// \brief A fancy ArrayHandle that turns a vector array into a scalar array by /// slicing out a single component of each vector. /// diff --git a/vtkm/cont/ArrayHandleExtrudeCoords.h b/vtkm/cont/ArrayHandleExtrudeCoords.h index 99315e383..16cc6974d 100644 --- a/vtkm/cont/ArrayHandleExtrudeCoords.h +++ b/vtkm/cont/ArrayHandleExtrudeCoords.h @@ -14,11 +14,17 @@ #include +#include + namespace vtkm { namespace cont { +template +VTKM_ARRAY_HANDLE_DEPRECATED(VTKM_PASS_COMMAS(vtkm::Vec), + vtkm::cont::internal::StorageTagExtrude); + template class VTKM_ALWAYS_EXPORT ArrayHandleExtrudeCoords : public vtkm::cont::ArrayHandle, internal::StorageTagExtrude> diff --git a/vtkm/cont/ArrayHandleExtrudeField.h b/vtkm/cont/ArrayHandleExtrudeField.h index 4bedd6e60..5c96c3046 100644 --- a/vtkm/cont/ArrayHandleExtrudeField.h +++ b/vtkm/cont/ArrayHandleExtrudeField.h @@ -13,11 +13,16 @@ #include #include +#include + namespace vtkm { namespace cont { +template +VTKM_ARRAY_HANDLE_DEPRECATED(T, vtkm::cont::internal::StorageTagExtrude); + template class VTKM_ALWAYS_EXPORT ArrayHandleExtrudeField : public vtkm::cont::ArrayHandle diff --git a/vtkm/cont/ArrayHandleGroupVec.h b/vtkm/cont/ArrayHandleGroupVec.h index f3658e9d9..d87c7a4d7 100644 --- a/vtkm/cont/ArrayHandleGroupVec.h +++ b/vtkm/cont/ArrayHandleGroupVec.h @@ -174,9 +174,6 @@ public: } // namespace internal -template -VTKM_ARRAY_HANDLE_NEW_STYLE(T, VTKM_PASS_COMMAS(vtkm::cont::StorageTagGroupVec)); - /// \brief Fancy array handle that groups values into vectors. /// /// It is sometimes the case that an array is stored such that consecutive diff --git a/vtkm/cont/ArrayHandleGroupVecVariable.h b/vtkm/cont/ArrayHandleGroupVecVariable.h index 964b0af67..d8b178fb7 100644 --- a/vtkm/cont/ArrayHandleGroupVecVariable.h +++ b/vtkm/cont/ArrayHandleGroupVecVariable.h @@ -211,9 +211,6 @@ public: } // namespace internal -template -VTKM_ARRAY_HANDLE_NEW_STYLE(T, VTKM_PASS_COMMAS(vtkm::cont::StorageTagGroupVecVariable)); - /// \brief Fancy array handle that groups values into vectors of different sizes. /// /// It is sometimes the case that you need to run a worklet with an input or diff --git a/vtkm/cont/ArrayHandleImplicit.h b/vtkm/cont/ArrayHandleImplicit.h index 099713e7b..29f7be13a 100644 --- a/vtkm/cont/ArrayHandleImplicit.h +++ b/vtkm/cont/ArrayHandleImplicit.h @@ -160,11 +160,6 @@ struct ArrayHandleImplicitTraits } // namespace detail -// This can go away once ArrayHandle is replaced with ArrayHandleNewStyle -template -VTKM_ARRAY_HANDLE_NEW_STYLE(typename PortalType::ValueType, - vtkm::cont::StorageTagImplicit); - /// \brief An \c ArrayHandle that computes values on the fly. /// /// \c ArrayHandleImplicit is a specialization of ArrayHandle. diff --git a/vtkm/cont/ArrayHandleIndex.h b/vtkm/cont/ArrayHandleIndex.h index 4a152b77e..d5dcc0fc9 100644 --- a/vtkm/cont/ArrayHandleIndex.h +++ b/vtkm/cont/ArrayHandleIndex.h @@ -45,9 +45,6 @@ struct Storage : Storage -VTKM_ARRAY_HANDLE_NEW_STYLE(vtkm::Id, vtkm::cont::StorageTagIndex); - /// \brief An implicit array handle containing the its own indices. /// /// \c ArrayHandleIndex is an implicit array handle containing the values diff --git a/vtkm/cont/ArrayHandleMultiplexer.h b/vtkm/cont/ArrayHandleMultiplexer.h index 6be9c46de..571efffd1 100644 --- a/vtkm/cont/ArrayHandleMultiplexer.h +++ b/vtkm/cont/ArrayHandleMultiplexer.h @@ -353,9 +353,6 @@ struct ArrayHandleMultiplexerTraits }; } // namespace detail -template -VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagMultiplexer); - /// \brief An ArrayHandle that can behave like several other handles. /// /// An \c ArrayHandleMultiplexer simply redirects its calls to another \c ArrayHandle. However diff --git a/vtkm/cont/ArrayHandlePermutation.h b/vtkm/cont/ArrayHandlePermutation.h index a9faa5984..37888b8d1 100644 --- a/vtkm/cont/ArrayHandlePermutation.h +++ b/vtkm/cont/ArrayHandlePermutation.h @@ -172,9 +172,6 @@ public: } // namespace internal -template -VTKM_ARRAY_HANDLE_NEW_STYLE(T, VTKM_PASS_COMMAS(vtkm::cont::StorageTagPermutation)); - /// \brief Implicitly permutes the values in an array. /// /// ArrayHandlePermutation is a specialization of ArrayHandle. It takes two diff --git a/vtkm/cont/ArrayHandleRecombineVec.h b/vtkm/cont/ArrayHandleRecombineVec.h index 334fe0ee3..4a79a6337 100644 --- a/vtkm/cont/ArrayHandleRecombineVec.h +++ b/vtkm/cont/ArrayHandleRecombineVec.h @@ -386,9 +386,6 @@ public: } // namespace internal -template -VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::internal::StorageTagRecombineVec); - /// \brief A grouping of `ArrayHandleStride`s into an `ArrayHandle` of `Vec`s. /// /// The main intention of `ArrayHandleStride` is to pull out a component of an diff --git a/vtkm/cont/ArrayHandleReverse.h b/vtkm/cont/ArrayHandleReverse.h index 993eddb40..f39b13682 100644 --- a/vtkm/cont/ArrayHandleReverse.h +++ b/vtkm/cont/ArrayHandleReverse.h @@ -163,9 +163,6 @@ public: } // namespace internal -template -VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagReverse); - /// \brief Reverse the order of an array, on demand. /// /// ArrayHandleReverse is a specialization of ArrayHandle. Given an ArrayHandle, diff --git a/vtkm/cont/ArrayHandleSOA.h b/vtkm/cont/ArrayHandleSOA.h index 77cc8ec17..0498e6cac 100644 --- a/vtkm/cont/ArrayHandleSOA.h +++ b/vtkm/cont/ArrayHandleSOA.h @@ -204,9 +204,6 @@ public: } // namespace internal -template -VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagSOA); - /// \brief An `ArrayHandle` that for Vecs stores each component in a separate physical array. /// /// `ArrayHandleSOA` behaves like a regular `ArrayHandle` (with a basic storage) except that diff --git a/vtkm/cont/ArrayHandleStride.cxx b/vtkm/cont/ArrayHandleStride.cxx index 5587c46f9..e6a84e597 100644 --- a/vtkm/cont/ArrayHandleStride.cxx +++ b/vtkm/cont/ArrayHandleStride.cxx @@ -33,17 +33,17 @@ template class VTKM_CONT_EXPORT Storage; } // namespace internal -template class VTKM_CONT_EXPORT ArrayHandleNewStyle; -template class VTKM_CONT_EXPORT ArrayHandleNewStyle; -template class VTKM_CONT_EXPORT ArrayHandleNewStyle; -template class VTKM_CONT_EXPORT ArrayHandleNewStyle; -template class VTKM_CONT_EXPORT ArrayHandleNewStyle; -template class VTKM_CONT_EXPORT ArrayHandleNewStyle; -template class VTKM_CONT_EXPORT ArrayHandleNewStyle; -template class VTKM_CONT_EXPORT ArrayHandleNewStyle; -template class VTKM_CONT_EXPORT ArrayHandleNewStyle; -template class VTKM_CONT_EXPORT ArrayHandleNewStyle; -template class VTKM_CONT_EXPORT ArrayHandleNewStyle; +template class VTKM_CONT_EXPORT ArrayHandle; +template class VTKM_CONT_EXPORT ArrayHandle; +template class VTKM_CONT_EXPORT ArrayHandle; +template class VTKM_CONT_EXPORT ArrayHandle; +template class VTKM_CONT_EXPORT ArrayHandle; +template class VTKM_CONT_EXPORT ArrayHandle; +template class VTKM_CONT_EXPORT ArrayHandle; +template class VTKM_CONT_EXPORT ArrayHandle; +template class VTKM_CONT_EXPORT ArrayHandle; +template class VTKM_CONT_EXPORT ArrayHandle; +template class VTKM_CONT_EXPORT ArrayHandle; } } // namespace vtkm::cont diff --git a/vtkm/cont/ArrayHandleStride.h b/vtkm/cont/ArrayHandleStride.h index fe03892e8..73b3d612d 100644 --- a/vtkm/cont/ArrayHandleStride.h +++ b/vtkm/cont/ArrayHandleStride.h @@ -205,9 +205,6 @@ public: } // namespace internal -template -VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagStride); - /// \brief An `ArrayHandle` that accesses a basic array with strides and offsets. /// /// `ArrayHandleStride` is a simple `ArrayHandle` that accesses data with a prescribed @@ -393,19 +390,17 @@ extern template class VTKM_CONT_TEMPLATE_EXPORT Storage; -extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleNewStyle; -extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleNewStyle; -extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleNewStyle; -extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleNewStyle; -extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleNewStyle; -extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleNewStyle; -extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleNewStyle; -extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleNewStyle; -extern template class VTKM_CONT_TEMPLATE_EXPORT - ArrayHandleNewStyle; -extern template class VTKM_CONT_TEMPLATE_EXPORT - ArrayHandleNewStyle; +extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle; +extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle; +extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle; +extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle; +extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle; +extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle; +extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle; +extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle; +extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle; +extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle; +extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle; } } // namespace vtkm::cont diff --git a/vtkm/cont/ArrayHandleTransform.h b/vtkm/cont/ArrayHandleTransform.h index cd8d4a970..43fad72e8 100644 --- a/vtkm/cont/ArrayHandleTransform.h +++ b/vtkm/cont/ArrayHandleTransform.h @@ -416,9 +416,6 @@ public: } // namespace internal -template -VTKM_ARRAY_HANDLE_NEW_STYLE(T, VTKM_PASS_COMMAS(internal::StorageTagTransform)); - /// \brief Implicitly transform values of one array to another with a functor. /// /// ArrayHandleTransforms is a specialization of ArrayHandle. It takes a diff --git a/vtkm/cont/ArrayHandleUniformPointCoordinates.h b/vtkm/cont/ArrayHandleUniformPointCoordinates.h index c609f4e1f..ebbf18975 100644 --- a/vtkm/cont/ArrayHandleUniformPointCoordinates.h +++ b/vtkm/cont/ArrayHandleUniformPointCoordinates.h @@ -37,9 +37,6 @@ struct Storage } // namespace internal -template <> -VTKM_ARRAY_HANDLE_NEW_STYLE(vtkm::Vec3f, vtkm::cont::StorageTagUniformPoints); - /// ArrayHandleUniformPointCoordinates is a specialization of ArrayHandle. It /// contains the information necessary to compute the point coordinates in a /// uniform orthogonal grid (extent, origin, and spacing) and implicitly diff --git a/vtkm/cont/ArrayHandleView.h b/vtkm/cont/ArrayHandleView.h index 8bde9b250..a66844880 100644 --- a/vtkm/cont/ArrayHandleView.h +++ b/vtkm/cont/ArrayHandleView.h @@ -196,10 +196,6 @@ public: } // namespace internal -// This can go away once ArrayHandle is replaced with ArrayHandleNewStyle -template -VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagView); - template class ArrayHandleView : public vtkm::cont::ArrayHandle #include #include - #include +#include + #include #ifdef VTKM_NO_DEPRECATED_VIRTUAL @@ -29,8 +30,11 @@ namespace vtkm namespace cont { - VTKM_DEPRECATED_SUPPRESS_BEGIN + +template +VTKM_ARRAY_HANDLE_DEPRECATED(T, vtkm::cont::StorageTagVirtual); + template class VTKM_ALWAYS_EXPORT VTKM_DEPRECATED(1.6) ArrayHandleVirtual : public vtkm::cont::ArrayHandle diff --git a/vtkm/cont/ArrayHandleZip.h b/vtkm/cont/ArrayHandleZip.h index bfe5338cc..eba3e2918 100644 --- a/vtkm/cont/ArrayHandleZip.h +++ b/vtkm/cont/ArrayHandleZip.h @@ -201,10 +201,6 @@ public: }; } // namespace internal -template -VTKM_ARRAY_HANDLE_NEW_STYLE(VTKM_PASS_COMMAS(vtkm::Pair), - VTKM_PASS_COMMAS(vtkm::cont::StorageTagZip)); - /// ArrayHandleZip is a specialization of ArrayHandle. It takes two delegate /// array handle and makes a new handle that access the corresponding entries /// in these arrays as a pair. diff --git a/vtkm/cont/CMakeLists.txt b/vtkm/cont/CMakeLists.txt index 6ce20aac6..bcfed4442 100644 --- a/vtkm/cont/CMakeLists.txt +++ b/vtkm/cont/CMakeLists.txt @@ -127,7 +127,6 @@ set(headers ) set(template_sources - ArrayHandle.hxx ArrayRangeCompute.hxx # Deprecated, replaced with ArrayRangeComputeTemplate.h CellSetExplicit.hxx CellSetExtrude.hxx diff --git a/vtkm/cont/StorageExtrude.h b/vtkm/cont/StorageExtrude.h index b9f46431c..97ad5c24a 100644 --- a/vtkm/cont/StorageExtrude.h +++ b/vtkm/cont/StorageExtrude.h @@ -16,6 +16,9 @@ #include +#include +#include + #include #include diff --git a/vtkm/cont/StorageVirtual.h b/vtkm/cont/StorageVirtual.h index ec3af2bd8..a2a609244 100644 --- a/vtkm/cont/StorageVirtual.h +++ b/vtkm/cont/StorageVirtual.h @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include #include diff --git a/vtkm/cont/StorageVirtual.hxx b/vtkm/cont/StorageVirtual.hxx index 80b9e4ade..9a0ef3880 100644 --- a/vtkm/cont/StorageVirtual.hxx +++ b/vtkm/cont/StorageVirtual.hxx @@ -12,8 +12,9 @@ #include #include -#include +#include +#include #include #include diff --git a/vtkm/cont/internal/ArrayHandleDeprecated.h b/vtkm/cont/internal/ArrayHandleDeprecated.h new file mode 100644 index 000000000..94386868d --- /dev/null +++ b/vtkm/cont/internal/ArrayHandleDeprecated.h @@ -0,0 +1,1354 @@ +//============================================================================ +// 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. +//============================================================================ +#ifndef vtk_m_cont_internal_ArrayHandleDeprecated_h +#define vtk_m_cont_internal_ArrayHandleDeprecated_h + +#include + +#include +#include + +namespace vtkm +{ +namespace cont +{ +namespace internal +{ + +/// The `ArrayHandle` implementation was recently significantly changed. +/// Implementations still using the old style should use this version. +/// These implementations should be deprecated. +/// +template +class VTKM_ALWAYS_EXPORT ArrayHandleDeprecated : public internal::ArrayHandleBase +{ +private: + // Basic storage is specialized; this template should not be instantiated + // for it. Specialization is in ArrayHandleBasicImpl.h + static_assert(!std::is_same::value, + "StorageTagBasic should not use this implementation."); + + using ExecutionManagerType = + vtkm::cont::internal::ArrayHandleExecutionManagerBase; + + using MutexType = std::mutex; + using LockType = std::unique_lock; + + mutable vtkm::cont::internal::Buffer BufferAsStorageWrapper; + +public: + using StorageType = vtkm::cont::internal::Storage; + using ValueType = T; + using StorageTag = StorageTag_; + using WritePortalType = typename StorageType::PortalType; + using ReadPortalType = typename StorageType::PortalConstType; + template + struct ExecutionTypes + { + using Portal = typename ExecutionManagerType::template ExecutionTypes::Portal; + using PortalConst = + typename ExecutionManagerType::template ExecutionTypes::PortalConst; + }; + + using PortalControl VTKM_DEPRECATED(1.6, "Use ArrayHandle::WritePortalType instead.") = + typename StorageType::PortalType; + using PortalConstControl VTKM_DEPRECATED(1.6, "Use ArrayHandle::ReadPortalType instead.") = + typename StorageType::PortalConstType; + + // Handle the fact that the ArrayHandle design has changed. + VTKM_STATIC_ASSERT_MSG((std::is_same::value), + "ArrayHandle design has changed. To support old-style arrays, have the " + "Storage implementation subclass StorageDeprecated."); + VTKM_CONT static constexpr vtkm::IdComponent GetNumberOfBuffers() { return 1; } + VTKM_CONT vtkm::cont::internal::Buffer* GetBuffers() const + { + this->BufferAsStorageWrapper.SetMetaData(*this); + return &this->BufferAsStorageWrapper; + } + + VTKM_CONT ArrayHandleDeprecated(const vtkm::cont::internal::Buffer* buffers) + { + VTKM_ASSERT(buffers[0].MetaDataIsType()); + *this = buffers[0].GetMetaData(); + } + + /// Constructs an empty ArrayHandleDeprecated. Typically used for output or + /// intermediate arrays that will be filled by a VTKm algorithm. + /// + VTKM_CONT ArrayHandleDeprecated(); + + /// Copy constructor. + /// + /// Implemented so that it is defined exclusively in the control environment. + /// If there is a separate device for the execution environment (for example, + /// with CUDA), then the automatically generated copy constructor could be + /// created for all devices, and it would not be valid for all devices. + /// + ArrayHandleDeprecated(const ArrayHandleDeprecated& src); + + /// Move constructor. + /// + /// Implemented so that it is defined exclusively in the control environment. + /// If there is a separate device for the execution environment (for example, + /// with CUDA), then the automatically generated move constructor could be + /// created for all devices, and it would not be valid for all devices. + /// + ArrayHandleDeprecated(ArrayHandleDeprecated&& src) noexcept; + + /// Special constructor for subclass specializations that need to set the + /// initial state of the control array. When this constructor is used, it + /// is assumed that the control array is valid. + /// + ArrayHandleDeprecated(const StorageType& storage); + + + /// Special constructor for subclass specializations that need to set the + /// initial state of the control array. When this constructor is used, it + /// is assumed that the control array is valid. + /// + ArrayHandleDeprecated(StorageType&& storage) noexcept; + + /// Destructs an empty ArrayHandleDeprecated. + /// + /// Implemented so that it is defined exclusively in the control environment. + /// If there is a separate device for the execution environment (for example, + /// with CUDA), then the automatically generated destructor could be + /// created for all devices, and it would not be valid for all devices. + /// + ~ArrayHandleDeprecated(); + + /// \brief Copies an ArrayHandleDeprecated + /// + VTKM_CONT + ArrayHandleDeprecated& operator=( + const ArrayHandleDeprecated& src); + + /// \brief Move and Assignment of an ArrayHandleDeprecated + /// + VTKM_CONT + ArrayHandleDeprecated& operator=( + ArrayHandleDeprecated&& src) noexcept; + + /// Like a pointer, two \c ArrayHandles are considered equal if they point + /// to the same location in memory. + /// + VTKM_CONT + bool operator==(const ArrayHandleDeprecated& rhs) const + { + return (this->Internals == rhs.Internals); + } + + VTKM_CONT + bool operator!=(const ArrayHandleDeprecated& rhs) const + { + return (this->Internals != rhs.Internals); + } + + VTKM_CONT bool operator==(const vtkm::cont::ArrayHandle& rhs) const + { + return *this == static_cast>(rhs); + } + + VTKM_CONT bool operator!=(const vtkm::cont::ArrayHandle& rhs) const + { + return *this != static_cast>(rhs); + } + + template + VTKM_CONT bool operator==(const ArrayHandleDeprecated&) const + { + return false; // different valuetype and/or storage + } + + template + VTKM_CONT bool operator!=(const ArrayHandleDeprecated&) const + { + return true; // different valuetype and/or storage + } + + template + VTKM_CONT bool operator==(const vtkm::cont::ArrayHandle&) const + { + return false; // different storage + } + + template + VTKM_CONT bool operator!=(const vtkm::cont::ArrayHandle&) const + { + return false; // different storage + } + + /// Get the storage. + /// + VTKM_CONT StorageType& GetStorage(); + + /// Get the storage. + /// + VTKM_CONT const StorageType& GetStorage() const; + + /// Get the array portal of the control array. + /// Since worklet invocations are asynchronous and this routine is a synchronization point, + /// exceptions maybe thrown for errors from previously executed worklets. + /// + /// \deprecated Use `WritePortal` instead. Note that the portal returned from `WritePortal` + /// will disallow any other reads or writes to the array while it is in scope. + /// + VTKM_CONT + VTKM_DEPRECATED(1.6, + "Use ArrayHandle::WritePortal() instead. " + "Note that the returned portal will lock the array while it is in scope.") + + /// \cond NOPE + typename StorageType::PortalType GetPortalControl(); + /// \endcond + + /// Get the array portal of the control array. + /// Since worklet invocations are asynchronous and this routine is a synchronization point, + /// exceptions maybe thrown for errors from previously executed worklets. + /// + /// \deprecated Use `ReadPortal` instead. Note that the portal returned from `ReadPortal` + /// will disallow any writes to the array while it is in scope. + /// + VTKM_CONT + VTKM_DEPRECATED(1.6, + "Use ArrayHandle::ReadPortal() instead. " + "Note that the returned portal will lock the array while it is in scope.") + /// \cond NOPE + typename StorageType::PortalConstType GetPortalConstControl() const; + /// \endcond + + /// \@{ + /// \brief Get an array portal that can be used in the control environment. + /// + /// The returned array can be used in the control environment to read values from the array. (It + /// is not possible to write to the returned portal. That is `Get` will work on the portal, but + /// `Set` will not.) + /// + /// **Note:** The returned portal cannot be used in the execution environment. This is because + /// the portal will not work on some devices like GPUs. To get a portal that will work in the + /// execution environment, use `PrepareForInput`. + /// + VTKM_CONT ReadPortalType ReadPortal() const; + /// \@} + + /// \@{ + /// \brief Get an array portal that can be used in the control environment. + /// + /// The returned array can be used in the control environment to reand and write values to the + /// array. + /// + /// + /// **Note:** The returned portal cannot be used in the execution environment. This is because + /// the portal will not work on some devices like GPUs. To get a portal that will work in the + /// execution environment, use `PrepareForInput`. + /// + VTKM_CONT WritePortalType WritePortal() const; + /// \@} + + /// Returns the number of entries in the array. + /// + VTKM_CONT vtkm::Id GetNumberOfValues() const + { + LockType lock = this->GetLock(); + + return this->GetNumberOfValues(lock); + } + + /// \brief Allocates an array large enough to hold the given number of values. + /// + /// The allocation may be done on an already existing array, but can wipe out + /// any data already in the array. This method can throw + /// ErrorBadAllocation if the array cannot be allocated or + /// ErrorBadValue if the allocation is not feasible (for example, the + /// array storage is read-only). + /// + VTKM_CONT + void Allocate(vtkm::Id numberOfValues) + { + vtkm::cont::Token token; + this->Allocate(numberOfValues, token); + } + VTKM_CONT void Allocate(vtkm::Id numberOfValues, vtkm::cont::Token& token) + { + LockType lock = this->GetLock(); + this->WaitToWrite(lock, token); + this->ReleaseResourcesExecutionInternal(lock, token); + this->Internals->GetControlArray(lock)->Allocate(numberOfValues); + // Set to false and then to true to ensure anything pointing to an array before the allocate + // is invalidated. + this->Internals->SetControlArrayValid(lock, false); + this->Internals->SetControlArrayValid(lock, true); + } + + /// \brief Reduces the size of the array without changing its values. + /// + /// This method allows you to resize the array without reallocating it. The + /// number of entries in the array is changed to \c numberOfValues. The data + /// in the array (from indices 0 to \c numberOfValues - 1) are the same, but + /// \c numberOfValues must be equal or less than the preexisting size + /// (returned from GetNumberOfValues). That is, this method can only be used + /// to shorten the array, not lengthen. + VTKM_CONT void Shrink(vtkm::Id numberOfValues) + { + vtkm::cont::Token token; + this->Shrink(numberOfValues, token); + } + VTKM_CONT void Shrink(vtkm::Id numberOfValues, vtkm::cont::Token& token); + + /// Releases any resources being used in the execution environment (that are + /// not being shared by the control environment). + /// + VTKM_CONT void ReleaseResourcesExecution() + { + // A Token should not be declared within the scope of a lock. when the token goes out of scope + // it will attempt to aquire the lock, which is undefined behavior of the thread already has + // the lock. + vtkm::cont::Token token; + { + LockType lock = this->GetLock(); + this->WaitToWrite(lock, token); + + // Save any data in the execution environment by making sure it is synced + // with the control environment. + this->SyncControlArray(lock, token); + + this->ReleaseResourcesExecutionInternal(lock, token); + } + } + + /// Releases all resources in both the control and execution environments. + /// + VTKM_CONT void ReleaseResources() + { + // A Token should not be declared within the scope of a lock. when the token goes out of scope + // it will attempt to aquire the lock, which is undefined behavior of the thread already has + // the lock. + vtkm::cont::Token token; + { + LockType lock = this->GetLock(); + + this->ReleaseResourcesExecutionInternal(lock, token); + + if (this->Internals->IsControlArrayValid(lock)) + { + this->Internals->GetControlArray(lock)->ReleaseResources(); + this->Internals->SetControlArrayValid(lock, false); + } + } + } + + /// Prepares this array to be used as an input to an operation in the + /// execution environment. If necessary, copies data to the execution + /// environment. Can throw an exception if this array does not yet contain + /// any data. Returns a portal that can be used in code running in the + /// execution environment. + /// + /// The `Token` object provided will be attached to this `ArrayHandle`. + /// The returned portal is guaranteed to be valid while the `Token` is + /// still attached and in scope. Other operations on this `ArrayHandle` + /// that would invalidate the returned portal will block until the `Token` + /// is released. Likewise, this method will block if another `Token` is + /// already attached. This can potentially lead to deadlocks. + /// + template + VTKM_CONT typename ExecutionTypes::PortalConst PrepareForInput( + DeviceAdapterTag, + vtkm::cont::Token& token) const; + + /// Prepares (allocates) this array to be used as an output from an operation + /// in the execution environment. The internal state of this class is set to + /// have valid data in the execution array with the assumption that the array + /// will be filled soon (i.e. before any other methods of this object are + /// called). Returns a portal that can be used in code running in the + /// execution environment. + /// + /// The `Token` object provided will be attached to this `ArrayHandle`. + /// The returned portal is guaranteed to be valid while the `Token` is + /// still attached and in scope. Other operations on this `ArrayHandle` + /// that would invalidate the returned portal will block until the `Token` + /// is released. Likewise, this method will block if another `Token` is + /// already attached. This can potentially lead to deadlocks. + /// + template + VTKM_CONT typename ExecutionTypes::Portal + PrepareForOutput(vtkm::Id numberOfValues, DeviceAdapterTag, vtkm::cont::Token& token); + + /// Prepares this array to be used in an in-place operation (both as input + /// and output) in the execution environment. If necessary, copies data to + /// the execution environment. Can throw an exception if this array does not + /// yet contain any data. Returns a portal that can be used in code running + /// in the execution environment. + /// + /// The `Token` object provided will be attached to this `ArrayHandle`. + /// The returned portal is guaranteed to be valid while the `Token` is + /// still attached and in scope. Other operations on this `ArrayHandle` + /// that would invalidate the returned portal will block until the `Token` + /// is released. Likewise, this method will block if another `Token` is + /// already attached. This can potentially lead to deadlocks. + /// + template + VTKM_CONT typename ExecutionTypes::Portal PrepareForInPlace( + DeviceAdapterTag, + vtkm::cont::Token& token); + + template + VTKM_CONT VTKM_DEPRECATED(1.6, "PrepareForInput now requires a vtkm::cont::Token object.") + typename ExecutionTypes::PortalConst PrepareForInput(DeviceAdapterTag) const + { + vtkm::cont::Token token; + return this->PrepareForInput(DeviceAdapterTag{}, token); + } + template + VTKM_CONT VTKM_DEPRECATED(1.6, "PrepareForOutput now requires a vtkm::cont::Token object.") + typename ExecutionTypes::Portal + PrepareForOutput(vtkm::Id numberOfValues, DeviceAdapterTag) + { + vtkm::cont::Token token; + return this->PrepareForOutput(numberOfValues, DeviceAdapterTag{}, token); + } + template + VTKM_CONT VTKM_DEPRECATED(1.6, "PrepareForInPlace now requires a vtkm::cont::Token object.") + typename ExecutionTypes::Portal PrepareForInPlace(DeviceAdapterTag) + { + vtkm::cont::Token token; + return this->PrepareForInPlace(DeviceAdapterTag{}, token); + } + + /// Returns the DeviceAdapterId for the current device. If there is no device + /// with an up-to-date copy of the data, VTKM_DEVICE_ADAPTER_UNDEFINED is + /// returned. + /// + /// Note that in a multithreaded environment the validity of this result can + /// change. + VTKM_CONT + DeviceAdapterId GetDeviceAdapterId() const + { + LockType lock = this->GetLock(); + return this->Internals->IsExecutionArrayValid(lock) + ? this->Internals->GetExecutionArray(lock)->GetDeviceAdapterId() + : DeviceAdapterTagUndefined{}; + } + + /// Synchronizes the control array with the execution array. If either the + /// user array or control array is already valid, this method does nothing + /// (because the data is already available in the control environment). + /// Although the internal state of this class can change, the method is + /// declared const because logically the data does not. + /// + VTKM_CONT void SyncControlArray() const + { + // A Token should not be declared within the scope of a lock. when the token goes out of scope + // it will attempt to aquire the lock, which is undefined behavior of the thread already has + // the lock. + vtkm::cont::Token token; + { + LockType lock = this->GetLock(); + this->SyncControlArray(lock, token); + } + } + + /// \brief Enqueue a token for access to this ArrayHandle. + /// + /// This method places the given `Token` into the queue of `Token`s waiting for + /// access to this `ArrayHandle` and then returns immediately. When this token + /// is later used to get data from this `ArrayHandle` (for example, in a call to + /// `PrepareForInput`), it will use this place in the queue while waiting for + /// access. + /// + /// This method is to be used to ensure that a set of accesses to an `ArrayHandle` + /// that happen on multiple threads occur in a specified order. For example, if + /// you spawn of a job to modify data in an `ArrayHandle` and then spawn off a job + /// that reads that same data, you need to make sure that the first job gets + /// access to the `ArrayHandle` before the second. If they both just attempt to call + /// their respective `Prepare` methods, there is no guarantee which order they + /// will occur. Having the spawning thread first call this method will ensure the order. + /// + /// \warning After calling this method it is required to subsequently + /// call a method like one of the `Prepare` methods that attaches the token + /// to this `ArrayHandle`. Otherwise, the enqueued token will block any subsequent + /// access to the `ArrayHandle`, even if the `Token` is destroyed. + /// + VTKM_CONT void Enqueue(const vtkm::cont::Token& token) const; + +private: + /// Acquires a lock on the internals of this `ArrayHandle`. The calling + /// function should keep the returned lock and let it go out of scope + /// when the lock is no longer needed. + /// + LockType GetLock() const { return LockType(this->Internals->Mutex); } + + /// Returns true if read operations can currently be performed. + /// + VTKM_CONT bool CanRead(const LockType& lock, const vtkm::cont::Token& token) const; + + //// Returns true if write operations can currently be performed. + /// + VTKM_CONT bool CanWrite(const LockType& lock, const vtkm::cont::Token& token) const; + + //// Will block the current thread until a read can be performed. + /// + VTKM_CONT void WaitToRead(LockType& lock, vtkm::cont::Token& token) const; + + //// Will block the current thread until a write can be performed. + /// + VTKM_CONT void WaitToWrite(LockType& lock, vtkm::cont::Token& token, bool fakeRead = false) const; + + /// Gets this array handle ready to interact with the given device. If the + /// array handle has already interacted with this device, then this method + /// does nothing. Although the internal state of this class can change, the + /// method is declared const because logically the data does not. + /// + template + VTKM_CONT void PrepareForDevice(LockType& lock, vtkm::cont::Token& token, DeviceAdapterTag) const; + + /// Synchronizes the control array with the execution array. If either the + /// user array or control array is already valid, this method does nothing + /// (because the data is already available in the control environment). + /// Although the internal state of this class can change, the method is + /// declared const because logically the data does not. + /// + VTKM_CONT void SyncControlArray(LockType& lock, vtkm::cont::Token& token) const; + + vtkm::Id GetNumberOfValues(LockType& lock) const; + + VTKM_CONT + void ReleaseResourcesExecutionInternal(LockType& lock, vtkm::cont::Token& token) const + { + if (this->Internals->IsExecutionArrayValid(lock)) + { + this->WaitToWrite(lock, token); + // Note that it is possible that while waiting someone else deleted the execution array. + // That is why we check again. + } + if (this->Internals->IsExecutionArrayValid(lock)) + { + this->Internals->GetExecutionArray(lock)->ReleaseResources(); + this->Internals->SetExecutionArrayValid(lock, false); + } + } + + VTKM_CONT void Enqueue(const LockType& lock, const vtkm::cont::Token& token) const; + + class VTKM_ALWAYS_EXPORT InternalStruct + { + mutable StorageType ControlArray; + mutable std::shared_ptr ControlArrayValid; + + mutable std::unique_ptr ExecutionArray; + mutable bool ExecutionArrayValid = false; + + mutable vtkm::cont::Token::ReferenceCount ReadCount = 0; + mutable vtkm::cont::Token::ReferenceCount WriteCount = 0; + + mutable std::deque Queue; + + VTKM_CONT void CheckLock(const LockType& lock) const + { + VTKM_ASSERT((lock.mutex() == &this->Mutex) && (lock.owns_lock())); + } + + public: + MutexType Mutex; + std::condition_variable ConditionVariable; + + InternalStruct() = default; + InternalStruct(const StorageType& storage); + InternalStruct(StorageType&& storage); + + ~InternalStruct() + { + // It should not be possible to destroy this array if any tokens are still attached to it. + LockType lock(this->Mutex); + VTKM_ASSERT((*this->GetReadCount(lock) == 0) && (*this->GetWriteCount(lock) == 0)); + this->SetControlArrayValid(lock, false); + } + + // To access any feature in InternalStruct, you must have locked the mutex. You have + // to prove it by passing in a reference to a std::unique_lock. + VTKM_CONT bool IsControlArrayValid(const LockType& lock) const + { + this->CheckLock(lock); + if (!this->ControlArrayValid) + { + return false; + } + else + { + return *this->ControlArrayValid; + } + } + VTKM_CONT void SetControlArrayValid(const LockType& lock, bool value) + { + this->CheckLock(lock); + if (IsControlArrayValid(lock) == value) + { + return; + } + if (value) // ControlArrayValid == false or nullptr + { + // If we are changing the valid flag from false to true, then refresh the pointer. + // There may be array portals that already have a reference to the flag. Those portals + // will stay in an invalid state whereas new portals will go to a valid state. To + // handle both conditions, drop the old reference and create a new one. + this->ControlArrayValid.reset(new bool(true)); + } + else // value == false and ControlArrayValid == true + { + *this->ControlArrayValid = false; + } + } + VTKM_CONT std::shared_ptr GetControlArrayValidPointer(const LockType& lock) const + { + this->CheckLock(lock); + return this->ControlArrayValid; + } + VTKM_CONT StorageType* GetControlArray(const LockType& lock) const + { + this->CheckLock(lock); + return &this->ControlArray; + } + + VTKM_CONT bool IsExecutionArrayValid(const LockType& lock) const + { + this->CheckLock(lock); + return this->ExecutionArrayValid; + } + VTKM_CONT void SetExecutionArrayValid(const LockType& lock, bool value) + { + this->CheckLock(lock); + this->ExecutionArrayValid = value; + } + VTKM_CONT ExecutionManagerType* GetExecutionArray(const LockType& lock) const + { + this->CheckLock(lock); + return this->ExecutionArray.get(); + } + VTKM_CONT void DeleteExecutionArray(const LockType& lock) + { + this->CheckLock(lock); + this->ExecutionArray.reset(); + this->ExecutionArrayValid = false; + } + template + VTKM_CONT void NewExecutionArray(const LockType& lock, DeviceAdapterTag) + { + VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapterTag); + this->CheckLock(lock); + VTKM_ASSERT(this->ExecutionArray == nullptr); + VTKM_ASSERT(!this->ExecutionArrayValid); + this->ExecutionArray.reset( + new vtkm::cont::internal::ArrayHandleExecutionManager( + &this->ControlArray)); + } + VTKM_CONT vtkm::cont::Token::ReferenceCount* GetReadCount(const LockType& lock) const + { + this->CheckLock(lock); + return &this->ReadCount; + } + VTKM_CONT vtkm::cont::Token::ReferenceCount* GetWriteCount(const LockType& lock) const + { + this->CheckLock(lock); + return &this->WriteCount; + } + VTKM_CONT std::deque& GetQueue(const LockType& lock) const + { + this->CheckLock(lock); + return this->Queue; + } + }; + + VTKM_CONT + ArrayHandleDeprecated(const std::shared_ptr& i) + : Internals(i) + { + } + + std::shared_ptr Internals; +}; + +template +ArrayHandleDeprecated::InternalStruct::InternalStruct( + const typename ArrayHandleDeprecated::StorageType& storage) + : ControlArray(storage) + , ControlArrayValid(new bool(true)) + , ExecutionArrayValid(false) +{ +} + +template +ArrayHandleDeprecated::InternalStruct::InternalStruct( + typename ArrayHandleDeprecated::StorageType&& storage) + : ControlArray(std::move(storage)) + , ControlArrayValid(new bool(true)) + , ExecutionArrayValid(false) +{ +} + +template +ArrayHandleDeprecated::ArrayHandleDeprecated() + : Internals(std::make_shared()) +{ +} + +template +ArrayHandleDeprecated::ArrayHandleDeprecated(const ArrayHandleDeprecated& src) + : Internals(src.Internals) +{ +} + +template +ArrayHandleDeprecated::ArrayHandleDeprecated(ArrayHandleDeprecated&& src) noexcept + : Internals(std::move(src.Internals)) +{ +} + +template +ArrayHandleDeprecated::ArrayHandleDeprecated( + const typename ArrayHandleDeprecated::StorageType& storage) + : Internals(std::make_shared(storage)) +{ +} + +template +ArrayHandleDeprecated::ArrayHandleDeprecated( + typename ArrayHandleDeprecated::StorageType&& storage) noexcept + : Internals(std::make_shared(std::move(storage))) +{ +} + +template +ArrayHandleDeprecated::~ArrayHandleDeprecated() +{ +} + +template +ArrayHandleDeprecated& ArrayHandleDeprecated::operator=( + const ArrayHandleDeprecated& src) +{ + this->Internals = src.Internals; + return *this; +} + +template +ArrayHandleDeprecated& ArrayHandleDeprecated::operator=( + ArrayHandleDeprecated&& src) noexcept +{ + this->Internals = std::move(src.Internals); + return *this; +} + +template +typename ArrayHandleDeprecated::StorageType& ArrayHandleDeprecated::GetStorage() +{ + // A Token should not be declared within the scope of a lock. when the token goes out of scope + // it will attempt to aquire the lock, which is undefined behavior of the thread already has + // the lock. + vtkm::cont::Token token; + { + LockType lock = this->GetLock(); + + this->SyncControlArray(lock, token); + if (this->Internals->IsControlArrayValid(lock)) + { + return *this->Internals->GetControlArray(lock); + } + else + { + throw vtkm::cont::ErrorInternal( + "ArrayHandle::SyncControlArray did not make control array valid."); + } + } +} + +template +const typename ArrayHandleDeprecated::StorageType& ArrayHandleDeprecated::GetStorage() + const +{ + // A Token should not be declared within the scope of a lock. when the token goes out of scope + // it will attempt to aquire the lock, which is undefined behavior of the thread already has + // the lock. + vtkm::cont::Token token; + { + LockType lock = this->GetLock(); + + this->SyncControlArray(lock, token); + if (this->Internals->IsControlArrayValid(lock)) + { + return *this->Internals->GetControlArray(lock); + } + else + { + throw vtkm::cont::ErrorInternal( + "ArrayHandle::SyncControlArray did not make control array valid."); + } + } +} + +template +typename ArrayHandleDeprecated::StorageType::PortalType +ArrayHandleDeprecated::GetPortalControl() +{ + // A Token should not be declared within the scope of a lock. when the token goes out of scope + // it will attempt to aquire the lock, which is undefined behavior of the thread already has + // the lock. + vtkm::cont::Token token; + { + LockType lock = this->GetLock(); + + this->SyncControlArray(lock, token); + if (this->Internals->IsControlArrayValid(lock)) + { + // If the user writes into the iterator we return, then the execution + // array will become invalid. Play it safe and release the execution + // resources. (Use the const version to preserve the execution array.) + this->ReleaseResourcesExecutionInternal(lock, token); + return this->Internals->GetControlArray(lock)->GetPortal(); + } + else + { + throw vtkm::cont::ErrorInternal( + "ArrayHandle::SyncControlArray did not make control array valid."); + } + } +} + +template +typename ArrayHandleDeprecated::StorageType::PortalConstType +ArrayHandleDeprecated::GetPortalConstControl() const +{ + // A Token should not be declared within the scope of a lock. when the token goes out of scope + // it will attempt to aquire the lock, which is undefined behavior of the thread already has + // the lock. + vtkm::cont::Token token; + { + LockType lock = this->GetLock(); + + this->SyncControlArray(lock, token); + if (this->Internals->IsControlArrayValid(lock)) + { + return this->Internals->GetControlArray(lock)->GetPortalConst(); + } + else + { + throw vtkm::cont::ErrorInternal( + "ArrayHandle::SyncControlArray did not make control array valid."); + } + } +} + +template +typename ArrayHandleDeprecated::ReadPortalType ArrayHandleDeprecated::ReadPortal() const +{ + // A Token should not be declared within the scope of a lock. when the token goes out of scope + // it will attempt to aquire the lock, which is undefined behavior of the thread already has + // the lock. + vtkm::cont::Token token; + { + LockType lock = this->GetLock(); + this->WaitToRead(lock, token); + + this->SyncControlArray(lock, token); + if (this->Internals->IsControlArrayValid(lock)) + { + return ReadPortalType(this->Internals->GetControlArray(lock)->GetPortalConst()); + } + else + { + throw vtkm::cont::ErrorInternal( + "ArrayHandle::SyncControlArray did not make control array valid."); + } + } +} + +template +typename ArrayHandleDeprecated::WritePortalType ArrayHandleDeprecated::WritePortal() + const +{ + // A Token should not be declared within the scope of a lock. when the token goes out of scope + // it will attempt to aquire the lock, which is undefined behavior of the thread already has + // the lock. + vtkm::cont::Token token; + { + LockType lock = this->GetLock(); + this->WaitToWrite(lock, token); + + this->SyncControlArray(lock, token); + if (this->Internals->IsControlArrayValid(lock)) + { + // If the user writes into the iterator we return, then the execution + // array will become invalid. Play it safe and release the execution + // resources. (Use the const version to preserve the execution array.) + this->ReleaseResourcesExecutionInternal(lock, token); + return WritePortalType(this->Internals->GetControlArray(lock)->GetPortal()); + } + else + { + throw vtkm::cont::ErrorInternal( + "ArrayHandle::SyncControlArray did not make control array valid."); + } + } +} + +template +vtkm::Id ArrayHandleDeprecated::GetNumberOfValues(LockType& lock) const +{ + if (this->Internals->IsControlArrayValid(lock)) + { + return this->Internals->GetControlArray(lock)->GetNumberOfValues(); + } + else if (this->Internals->IsExecutionArrayValid(lock)) + { + return this->Internals->GetExecutionArray(lock)->GetNumberOfValues(); + } + else + { + return 0; + } +} + +template +void ArrayHandleDeprecated::Shrink(vtkm::Id numberOfValues, vtkm::cont::Token& token) +{ + VTKM_ASSERT(numberOfValues >= 0); + + if (numberOfValues > 0) + { + LockType lock = this->GetLock(); + + vtkm::Id originalNumberOfValues = this->GetNumberOfValues(lock); + + if (numberOfValues < originalNumberOfValues) + { + this->WaitToWrite(lock, token); + if (this->Internals->IsControlArrayValid(lock)) + { + this->Internals->GetControlArray(lock)->Shrink(numberOfValues); + } + if (this->Internals->IsExecutionArrayValid(lock)) + { + this->Internals->GetExecutionArray(lock)->Shrink(numberOfValues); + } + } + else if (numberOfValues == originalNumberOfValues) + { + // Nothing to do. + } + else // numberOfValues > originalNumberOfValues + { + throw vtkm::cont::ErrorBadValue("ArrayHandle::Shrink cannot be used to grow array."); + } + + VTKM_ASSERT(this->GetNumberOfValues(lock) == numberOfValues); + } + else // numberOfValues == 0 + { + // If we are shrinking to 0, there is nothing to save and we might as well + // free up memory. Plus, some storage classes expect that data will be + // deallocated when the size goes to zero. + this->Allocate(0, token); + } +} + +template +template +typename ArrayHandleDeprecated::template ExecutionTypes::PortalConst +ArrayHandleDeprecated::PrepareForInput(DeviceAdapterTag device, + vtkm::cont::Token& token) const +{ + VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapterTag); + + LockType lock = this->GetLock(); + this->WaitToRead(lock, token); + + if (!this->Internals->IsControlArrayValid(lock) && !this->Internals->IsExecutionArrayValid(lock)) + { + // Want to use an empty array. + // Set up ArrayHandle state so this actually works. + this->Internals->GetControlArray(lock)->Allocate(0); + this->Internals->SetControlArrayValid(lock, true); + } + + this->PrepareForDevice(lock, token, device); + auto portal = this->Internals->GetExecutionArray(lock)->PrepareForInput( + !this->Internals->IsExecutionArrayValid(lock), device, token); + + this->Internals->SetExecutionArrayValid(lock, true); + + return portal; +} + +template +template +typename ArrayHandleDeprecated::template ExecutionTypes::Portal +ArrayHandleDeprecated::PrepareForOutput(vtkm::Id numberOfValues, + DeviceAdapterTag device, + vtkm::cont::Token& token) +{ + VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapterTag); + + LockType lock = this->GetLock(); + this->WaitToWrite(lock, token); + + // Invalidate any control arrays. + // Should the control array resource be released? Probably not a good + // idea when shared with execution. + this->Internals->SetControlArrayValid(lock, false); + + this->PrepareForDevice(lock, token, device); + auto portal = + this->Internals->GetExecutionArray(lock)->PrepareForOutput(numberOfValues, device, token); + + // We are assuming that the calling code will fill the array using the + // iterators we are returning, so go ahead and mark the execution array as + // having valid data. (A previous version of this class had a separate call + // to mark the array as filled, but that was onerous to call at the the + // right time and rather pointless since it is basically always the case + // that the array is going to be filled before anything else. In this + // implementation the only access to the array is through the iterators + // returned from this method, so you would have to work to invalidate this + // assumption anyway.) + this->Internals->SetExecutionArrayValid(lock, true); + + return portal; +} + +template +template +typename ArrayHandleDeprecated::template ExecutionTypes::Portal +ArrayHandleDeprecated::PrepareForInPlace(DeviceAdapterTag device, vtkm::cont::Token& token) +{ + VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapterTag); + + LockType lock = this->GetLock(); + this->WaitToWrite(lock, token); + + if (!this->Internals->IsControlArrayValid(lock) && !this->Internals->IsExecutionArrayValid(lock)) + { + // Want to use an empty array. + // Set up ArrayHandle state so this actually works. + this->Internals->GetControlArray(lock)->Allocate(0); + this->Internals->SetControlArrayValid(lock, true); + } + + this->PrepareForDevice(lock, token, device); + auto portal = this->Internals->GetExecutionArray(lock)->PrepareForInPlace( + !this->Internals->IsExecutionArrayValid(lock), device, token); + + this->Internals->SetExecutionArrayValid(lock, true); + + // Invalidate any control arrays since their data will become invalid when + // the execution data is overwritten. Don't actually release the control + // array. It may be shared as the execution array. + this->Internals->SetControlArrayValid(lock, false); + + return portal; +} + +template +template +void ArrayHandleDeprecated::PrepareForDevice(LockType& lock, + vtkm::cont::Token& token, + DeviceAdapterTag device) const +{ + if (this->Internals->GetExecutionArray(lock) != nullptr) + { + if (this->Internals->GetExecutionArray(lock)->IsDeviceAdapter(DeviceAdapterTag())) + { + // Already have manager for correct device adapter. Nothing to do. + return; + } + else + { + // Have the wrong manager. Delete the old one and create a new one + // of the right type. (TODO: it would be possible for the array handle + // to hold references to execution arrays on multiple devices. When data + // are written on one devices, all the other devices should get cleared.) + + // BUG: There is a non-zero chance that while waiting for the write lock, another thread + // could change the ExecutionInterface, which would cause problems. In the future we should + // support multiple devices, in which case we would not have to delete one execution array + // to load another. + // BUG: The current implementation does not allow the ArrayHandle to be on two devices + // at the same time. Thus, it is not possible for two simultaneously read from the same + // ArrayHandle on two different devices. This might cause unexpected deadlocks. + this->WaitToWrite(lock, token, true); // Make sure no one is reading device array + this->SyncControlArray(lock, token); + // Need to change some state that does not change the logical state from + // an external point of view. + this->Internals->DeleteExecutionArray(lock); + } + } + + // Need to change some state that does not change the logical state from + // an external point of view. + this->Internals->NewExecutionArray(lock, device); +} + +template +void ArrayHandleDeprecated::SyncControlArray(LockType& lock, vtkm::cont::Token& token) const +{ + if (!this->Internals->IsControlArrayValid(lock)) + { + // It may be the case that `SyncControlArray` is called from a method that has a `Token`. + // However, if we are here, that `Token` should not already be attached to this array. + // If it were, then there should be no reason to move data arround (unless the `Token` + // was used when preparing for multiple devices, which it should not be used like that). + this->WaitToRead(lock, token); + + // Need to change some state that does not change the logical state from + // an external point of view. + if (this->Internals->IsExecutionArrayValid(lock)) + { + this->Internals->GetExecutionArray(lock)->RetrieveOutputData( + this->Internals->GetControlArray(lock)); + this->Internals->SetControlArrayValid(lock, true); + } + else + { + // This array is in the null state (there is nothing allocated), but + // the calling function wants to do something with the array. Put this + // class into a valid state by allocating an array of size 0. + this->Internals->GetControlArray(lock)->Allocate(0); + this->Internals->SetControlArrayValid(lock, true); + } + } +} + +template +bool ArrayHandleDeprecated::CanRead(const LockType& lock, + const vtkm::cont::Token& token) const +{ + // If the token is already attached to this array, then we allow reading. + if (token.IsAttached(this->Internals->GetWriteCount(lock)) || + token.IsAttached(this->Internals->GetReadCount(lock))) + { + return true; + } + + // If there is anyone else waiting at the top of the queue, we cannot access this array. + auto& queue = this->Internals->GetQueue(lock); + if (!queue.empty() && (queue.front() != token)) + { + return false; + } + + // No one else is waiting, so we can read the array as long as no one else is writing. + return (*this->Internals->GetWriteCount(lock) < 1); +} + +template +bool ArrayHandleDeprecated::CanWrite(const LockType& lock, + const vtkm::cont::Token& token) const +{ + // If the token is already attached to this array, then we allow writing. + if (token.IsAttached(this->Internals->GetWriteCount(lock)) || + token.IsAttached(this->Internals->GetReadCount(lock))) + { + return true; + } + + // If there is anyone else waiting at the top of the queue, we cannot access this array. + auto& queue = this->Internals->GetQueue(lock); + if (!queue.empty() && (queue.front() != token)) + { + return false; + } + + // No one else is waiting, so we can write the array as long as no one else is reading or writing. + return ((*this->Internals->GetWriteCount(lock) < 1) && + (*this->Internals->GetReadCount(lock) < 1)); +} + +template +void ArrayHandleDeprecated::WaitToRead(LockType& lock, vtkm::cont::Token& token) const +{ + this->Enqueue(lock, token); + + // Note that if you deadlocked here, that means that you are trying to do a read operation on an + // array where an object is writing to it. + this->Internals->ConditionVariable.wait( + lock, [&lock, &token, this] { return this->CanRead(lock, token); }); + + token.Attach(this->Internals, + this->Internals->GetReadCount(lock), + lock, + &this->Internals->ConditionVariable); + + // We successfully attached the token. Pop it off the queue. + auto& queue = this->Internals->GetQueue(lock); + if (!queue.empty() && queue.front() == token) + { + queue.pop_front(); + } +} + +template +void ArrayHandleDeprecated::WaitToWrite(LockType& lock, + vtkm::cont::Token& token, + bool fakeRead) const +{ + this->Enqueue(lock, token); + + // Note that if you deadlocked here, that means that you are trying to do a write operation on an + // array where an object is reading or writing to it. + this->Internals->ConditionVariable.wait( + lock, [&lock, &token, this] { return this->CanWrite(lock, token); }); + + if (!fakeRead) + { + token.Attach(this->Internals, + this->Internals->GetWriteCount(lock), + lock, + &this->Internals->ConditionVariable); + } + else + { + // A current feature limitation of ArrayHandle is that it can only exist on one device at + // a time. Thus, if a read request comes in for a different device, the prepare has to + // get satisfy a write lock to boot the array off the existing device. However, we don't + // want to attach the Token as a write lock because the resulting state is for reading only + // and others might also want to read. So, we have to pretend that this is a read lock even + // though we have to make a change to the array. + // + // The main point is, this condition is a hack that should go away once ArrayHandle supports + // multiple devices at once. + token.Attach(this->Internals, + this->Internals->GetReadCount(lock), + lock, + &this->Internals->ConditionVariable); + } + + // We successfully attached the token. Pop it off the queue. + auto& queue = this->Internals->GetQueue(lock); + if (!queue.empty() && queue.front() == token) + { + queue.pop_front(); + } +} + +template +void ArrayHandleDeprecated::Enqueue(const vtkm::cont::Token& token) const +{ + LockType lock = this->GetLock(); + this->Enqueue(lock, token); +} + +template +void ArrayHandleDeprecated::Enqueue(const LockType& lock, + const vtkm::cont::Token& token) const +{ + if (token.IsAttached(this->Internals->GetWriteCount(lock)) || + token.IsAttached(this->Internals->GetReadCount(lock))) + { + // Do not need to enqueue if we are already attached. + return; + } + + auto& queue = this->Internals->GetQueue(lock); + if (std::find(queue.begin(), queue.end(), token.GetReference()) != queue.end()) + { + // This token is already in the queue. + return; + } + + this->Internals->GetQueue(lock).push_back(token.GetReference()); +} + +// This macro is used to declare an ArrayHandle that uses the old, deprecated style of Storage +// that leverages ArrayTransfer. This macro will go away once all deprecated ArrayHandles +// that use it are replaced with the new style. To use this macro, first have a declaration +// of the template and then put the macro like this: +// +// template +// VTKM_ARRAY_HANDLE_DEPRECATED(T, vtkm::cont::StorageTagFoo); +// +// Don't forget to use VTKM_PASS_COMMAS if one of the macro arguments contains +// a template with multiple parameters. +#define VTKM_ARRAY_HANDLE_DEPRECATED(ValueType_, StorageTag_) \ + class VTKM_ALWAYS_EXPORT ArrayHandle \ + : public internal::ArrayHandleDeprecated \ + { \ + using Superclass = internal::ArrayHandleDeprecated; \ + \ + public: \ + VTKM_CONT \ + ArrayHandle() \ + : Superclass() \ + { \ + } \ + \ + VTKM_CONT \ + ArrayHandle(const ArrayHandle& src) \ + : Superclass(src) \ + { \ + } \ + \ + VTKM_CONT \ + ArrayHandle(ArrayHandle&& src) noexcept \ + : Superclass(std::move(src)) \ + { \ + } \ + \ + VTKM_CONT \ + ArrayHandle(const internal::ArrayHandleDeprecated& src) \ + : Superclass(src) \ + { \ + } \ + \ + VTKM_CONT \ + ArrayHandle(internal::ArrayHandleDeprecated&& src) noexcept \ + : Superclass(std::move(src)) \ + { \ + } \ + \ + VTKM_CONT ArrayHandle(const internal::Storage& storage) \ + : Superclass(storage) \ + { \ + } \ + \ + VTKM_CONT ArrayHandle(internal::Storage&& storage) \ + : Superclass(std::move(storage)) \ + { \ + } \ + \ + VTKM_CONT ArrayHandle(const vtkm::cont::internal::Buffer* buffers) \ + : Superclass(buffers) \ + { \ + } \ + \ + VTKM_CONT ArrayHandle(const std::vector& buffers) \ + : Superclass(buffers.data()) \ + { \ + } \ + \ + VTKM_CONT \ + ArrayHandle& operator=( \ + const ArrayHandle& src) \ + { \ + this->Superclass::operator=(src); \ + return *this; \ + } \ + \ + VTKM_CONT \ + ArrayHandle& operator=( \ + ArrayHandle&& src) noexcept \ + { \ + this->Superclass::operator=(std::move(src)); \ + return *this; \ + } \ + \ + VTKM_CONT ~ArrayHandle() {} \ + } + +} +} +} // namespace vtkm::cont::internal + +#endif //vtk_m_cont_internal_ArrayHandleDeprecated_h diff --git a/vtkm/cont/internal/CMakeLists.txt b/vtkm/cont/internal/CMakeLists.txt index 5c876851b..006e45f94 100644 --- a/vtkm/cont/internal/CMakeLists.txt +++ b/vtkm/cont/internal/CMakeLists.txt @@ -9,6 +9,7 @@ ##============================================================================ set(headers + ArrayHandleDeprecated.h ArrayHandleExecutionManager.h ArrayPortalFromIterators.h ArrayTransfer.h diff --git a/vtkm/cont/internal/StorageDeprecated.h b/vtkm/cont/internal/StorageDeprecated.h index 9fc0dce4f..2ffba8a03 100644 --- a/vtkm/cont/internal/StorageDeprecated.h +++ b/vtkm/cont/internal/StorageDeprecated.h @@ -25,12 +25,12 @@ namespace vtkm namespace cont { -template -class ArrayHandle; - namespace internal { +template +class ArrayHandleDeprecated; + namespace detail { @@ -98,7 +98,7 @@ class StorageDeprecated using T = typename detail::StorageTemplateParams::ValueType; using StorageTag = typename detail::StorageTemplateParams::StorageTag; - using ArrayType = vtkm::cont::ArrayHandle; + using ArrayType = vtkm::cont::internal::ArrayHandleDeprecated; VTKM_CONT static ArrayType GetArray(const vtkm::cont::internal::Buffer* buffers) { diff --git a/vtkm/cont/internal/testing/UnitTestBuffer.cxx b/vtkm/cont/internal/testing/UnitTestBuffer.cxx index 173e309b5..d0089928d 100644 --- a/vtkm/cont/internal/testing/UnitTestBuffer.cxx +++ b/vtkm/cont/internal/testing/UnitTestBuffer.cxx @@ -8,6 +8,7 @@ // PURPOSE. See the above copyright notice for more information. //============================================================================ +#include #include #include diff --git a/vtkm/cont/testing/TestingDeviceAdapter.h b/vtkm/cont/testing/TestingDeviceAdapter.h index 2ccb8d393..555b08fb6 100644 --- a/vtkm/cont/testing/TestingDeviceAdapter.h +++ b/vtkm/cont/testing/TestingDeviceAdapter.h @@ -29,6 +29,7 @@ #include #include +#include #include #include From 3228752b2d8b5ecccf087917be5fdffeed515eb1 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Thu, 7 Jan 2021 11:28:14 -0700 Subject: [PATCH 2/2] Fix error message when using deprecated storage When using the old style of storage, you need to declare it as the old style so that a bridge to the new style can be built in. You get a compile error message if this is not done. The previous message gave the wrong instructions. --- vtkm/cont/internal/ArrayHandleDeprecated.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vtkm/cont/internal/ArrayHandleDeprecated.h b/vtkm/cont/internal/ArrayHandleDeprecated.h index 94386868d..13debc4f3 100644 --- a/vtkm/cont/internal/ArrayHandleDeprecated.h +++ b/vtkm/cont/internal/ArrayHandleDeprecated.h @@ -65,7 +65,8 @@ public: // Handle the fact that the ArrayHandle design has changed. VTKM_STATIC_ASSERT_MSG((std::is_same::value), "ArrayHandle design has changed. To support old-style arrays, have the " - "Storage implementation subclass StorageDeprecated."); + "Storage implementation declare VTKM_STORAGE_OLD_STYLE at the bottom " + "of its implementation."); VTKM_CONT static constexpr vtkm::IdComponent GetNumberOfBuffers() { return 1; } VTKM_CONT vtkm::cont::internal::Buffer* GetBuffers() const {