vtk-m2/vtkm/cont/internal/ArrayHandleBasicImpl.hxx
Robert Maynard c123796949 VTK-m ArrayHandle can now take ownership of a user allocated memory location
Previously memory that was allocated outside of VTK-m was impossible to transfer to
VTK-m as we didn't know how to free it. By extending the ArrayHandle constructors
to support a Storage object that is being moved, we can clearly express that
the ArrayHandle now owns memory it didn't allocate.

Here is an example of how this is done:
```cpp
  T* buffer = new T[100];
  auto user_free_function = [](void* ptr) { delete[] static_cast<T*>(ptr); };

  vtkm::cont::internal::Storage<T, vtkm::cont::StorageTagBasic>
      storage(buffer, 100, user_free_function);
  vtkm::cont::ArrayHandle<T> arrayHandle(std::move(storage));
```
2018-04-04 11:28:25 -04:00

265 lines
8.0 KiB
C++

//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2017 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2017 UT-Battelle, LLC.
// Copyright 2017 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_cont_internal_ArrayHandleBasicImpl_hxx
#define vtk_m_cont_internal_ArrayHandleBasicImpl_hxx
#include <vtkm/cont/internal/ArrayHandleBasicImpl.h>
namespace vtkm
{
namespace cont
{
template <typename T>
ArrayHandle<T, StorageTagBasic>::ArrayHandle()
: Internals(new internal::ArrayHandleImpl(T{}))
{
}
template <typename T>
ArrayHandle<T, StorageTagBasic>::ArrayHandle(const Thisclass& src)
: Internals(src.Internals)
{
}
template <typename T>
ArrayHandle<T, StorageTagBasic>::ArrayHandle(Thisclass&& src)
: Internals(std::move(src.Internals))
{
}
template <typename T>
ArrayHandle<T, StorageTagBasic>::ArrayHandle(const StorageType& storage)
: Internals(new internal::ArrayHandleImpl(storage))
{
}
template <typename T>
ArrayHandle<T, StorageTagBasic>::ArrayHandle(StorageType&& storage)
: Internals(new internal::ArrayHandleImpl(std::move(storage)))
{
}
template <typename T>
ArrayHandle<T, StorageTagBasic>::~ArrayHandle()
{
}
template <typename T>
ArrayHandle<T, StorageTagBasic>& ArrayHandle<T, StorageTagBasic>::operator=(const Thisclass& src)
{
this->Internals = src.Internals;
return *this;
}
template <typename T>
ArrayHandle<T, StorageTagBasic>& ArrayHandle<T, StorageTagBasic>::operator=(Thisclass&& src)
{
this->Internals = std::move(src.Internals);
return *this;
}
template <typename T>
bool ArrayHandle<T, StorageTagBasic>::operator==(const Thisclass& rhs) const
{
return this->Internals == rhs.Internals;
}
template <typename T>
bool ArrayHandle<T, StorageTagBasic>::operator!=(const Thisclass& rhs) const
{
return this->Internals != rhs.Internals;
}
template <typename T>
template <typename VT, typename ST>
VTKM_CONT bool ArrayHandle<T, StorageTagBasic>::operator==(const ArrayHandle<VT, ST>&) const
{
return false; // different valuetype and/or storage
}
template <typename T>
template <typename VT, typename ST>
VTKM_CONT bool ArrayHandle<T, StorageTagBasic>::operator!=(const ArrayHandle<VT, ST>&) const
{
return true; // different valuetype and/or storage
}
template <typename T>
typename ArrayHandle<T, StorageTagBasic>::StorageType& ArrayHandle<T, StorageTagBasic>::GetStorage()
{
this->SyncControlArray();
this->Internals->CheckControlArrayValid();
//CheckControlArrayValid will throw an exception if this->Internals->ControlArrayValid
//is not valid
return *(static_cast<StorageType*>(this->Internals->ControlArray));
}
template <typename T>
const typename ArrayHandle<T, StorageTagBasic>::StorageType&
ArrayHandle<T, StorageTagBasic>::GetStorage() const
{
this->SyncControlArray();
this->Internals->CheckControlArrayValid();
//CheckControlArrayValid will throw an exception if this->Internals->ControlArrayValid
//is not valid
return *(static_cast<const StorageType*>(this->Internals->ControlArray));
}
template <typename T>
typename ArrayHandle<T, StorageTagBasic>::PortalControl
ArrayHandle<T, StorageTagBasic>::GetPortalControl()
{
this->SyncControlArray();
this->Internals->CheckControlArrayValid();
//CheckControlArrayValid will throw an exception if this->Internals->ControlArrayValid
//is not valid
// 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();
StorageType* privStorage = static_cast<StorageType*>(this->Internals->ControlArray);
return privStorage->GetPortal();
}
template <typename T>
typename ArrayHandle<T, StorageTagBasic>::PortalConstControl
ArrayHandle<T, StorageTagBasic>::GetPortalConstControl() const
{
this->SyncControlArray();
this->Internals->CheckControlArrayValid();
//CheckControlArrayValid will throw an exception if this->Internals->ControlArrayValid
//is not valid
StorageType* privStorage = static_cast<StorageType*>(this->Internals->ControlArray);
return privStorage->GetPortalConst();
}
template <typename T>
vtkm::Id ArrayHandle<T, StorageTagBasic>::GetNumberOfValues() const
{
return this->Internals->GetNumberOfValues(sizeof(T));
}
template <typename T>
void ArrayHandle<T, StorageTagBasic>::Allocate(vtkm::Id numberOfValues)
{
this->Internals->Allocate(numberOfValues, sizeof(T));
}
template <typename T>
void ArrayHandle<T, StorageTagBasic>::Shrink(vtkm::Id numberOfValues)
{
this->Internals->Shrink(numberOfValues, sizeof(T));
}
template <typename T>
void ArrayHandle<T, StorageTagBasic>::ReleaseResourcesExecution()
{
// Save any data in the execution environment by making sure it is synced
// with the control environment.
this->SyncControlArray();
this->Internals->ReleaseResourcesExecutionInternal();
}
template <typename T>
void ArrayHandle<T, StorageTagBasic>::ReleaseResources()
{
this->Internals->ReleaseResources();
}
template <typename T>
template <typename DeviceAdapterTag>
typename ArrayHandle<T, StorageTagBasic>::template ExecutionTypes<DeviceAdapterTag>::PortalConst
ArrayHandle<T, StorageTagBasic>::PrepareForInput(DeviceAdapterTag device) const
{
VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapterTag);
this->PrepareForDevice(device);
this->Internals->PrepareForInput(sizeof(T));
return PortalFactory<DeviceAdapterTag>::CreatePortalConst(
static_cast<T*>(this->Internals->ExecutionArray),
static_cast<T*>(this->Internals->ExecutionArrayEnd));
}
template <typename T>
template <typename DeviceAdapterTag>
typename ArrayHandle<T, StorageTagBasic>::template ExecutionTypes<DeviceAdapterTag>::Portal
ArrayHandle<T, StorageTagBasic>::PrepareForOutput(vtkm::Id numVals, DeviceAdapterTag device)
{
VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapterTag);
this->PrepareForDevice(device);
this->Internals->PrepareForOutput(numVals, sizeof(T));
return PortalFactory<DeviceAdapterTag>::CreatePortal(
static_cast<T*>(this->Internals->ExecutionArray),
static_cast<T*>(this->Internals->ExecutionArrayEnd));
}
template <typename T>
template <typename DeviceAdapterTag>
typename ArrayHandle<T, StorageTagBasic>::template ExecutionTypes<DeviceAdapterTag>::Portal
ArrayHandle<T, StorageTagBasic>::PrepareForInPlace(DeviceAdapterTag device)
{
VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapterTag);
this->PrepareForDevice(device);
this->Internals->PrepareForInPlace(sizeof(T));
return PortalFactory<DeviceAdapterTag>::CreatePortal(
static_cast<T*>(this->Internals->ExecutionArray),
static_cast<T*>(this->Internals->ExecutionArrayEnd));
}
template <typename T>
template <typename DeviceAdapterTag>
void ArrayHandle<T, StorageTagBasic>::PrepareForDevice(DeviceAdapterTag) const
{
DeviceAdapterId devId = DeviceAdapterTraits<DeviceAdapterTag>::GetId();
this->Internals->PrepareForDevice(devId, sizeof(T));
}
template <typename T>
DeviceAdapterId ArrayHandle<T, StorageTagBasic>::GetDeviceAdapterId() const
{
return this->Internals->GetDeviceAdapterId();
}
template <typename T>
void ArrayHandle<T, StorageTagBasic>::SyncControlArray() const
{
this->Internals->SyncControlArray(sizeof(T));
}
template <typename T>
void ArrayHandle<T, StorageTagBasic>::ReleaseResourcesExecutionInternal()
{
this->Internals->ReleaseResourcesExecutionInternal();
}
}
} // end namespace vtkm::cont
#endif // not vtk_m_cont_internal_ArrayHandleBasicImpl_hxx