vtk-m/vtkm/cont/StorageBasic.h
Robert Maynard 674fe1fbf2 StealArray now returns the array and free function as a Pair.
This helps reduces bugs when the callers ask to steal arrays
without getting the free function, or ask for the free function
after stealing the array.
2019-05-01 09:42:57 -04:00

248 lines
9.1 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.
//============================================================================
#ifndef vtk_m_cont_StorageBasic_h
#define vtk_m_cont_StorageBasic_h
#include <vtkm/Assert.h>
#include <vtkm/Pair.h>
#include <vtkm/Types.h>
#include <vtkm/cont/ErrorBadAllocation.h>
#include <vtkm/cont/ErrorBadValue.h>
#include <vtkm/cont/Storage.h>
#include <vtkm/cont/internal/ArrayPortalFromIterators.h>
namespace vtkm
{
namespace cont
{
/// A tag for the basic implementation of a Storage object.
struct VTKM_ALWAYS_EXPORT StorageTagBasic
{
};
namespace internal
{
/// Function that does all of VTK-m de-allocations for storage basic.
/// This is exists so that stolen arrays can call the correct free
/// function ( _aligned_malloc / cuda_free ).
VTKM_CONT_EXPORT void free_memory(void* ptr);
/// Class that does all of VTK-m allocations
/// for storage basic. This is exists so that
/// stolen arrays can call the correct free
/// function ( _aligned_malloc ) on windows
struct VTKM_CONT_EXPORT StorageBasicAllocator
{
void* allocate(size_t size, size_t align);
template <typename T>
inline void deallocate(T* p)
{
internal::free_memory(static_cast<void*>(p));
}
};
/// Base class for basic storage classes. This allow us to implement
/// vtkm::cont::Storage<T, StorageTagBasic > for any T type with no overhead
/// as all heavy logic is provide by a type-agnostic API including allocations, etc.
class VTKM_CONT_EXPORT StorageBasicBase
{
public:
using AllocatorType = StorageBasicAllocator;
VTKM_CONT StorageBasicBase();
/// A non owning view of already allocated memory
VTKM_CONT StorageBasicBase(const void* array, vtkm::Id size, vtkm::UInt64 sizeOfValue);
/// Transfer the ownership of already allocated memory to VTK-m
VTKM_CONT StorageBasicBase(const void* array,
vtkm::Id size,
vtkm::UInt64 sizeOfValue,
void (*deleteFunction)(void*));
VTKM_CONT ~StorageBasicBase();
VTKM_CONT StorageBasicBase(StorageBasicBase&& src) noexcept;
VTKM_CONT StorageBasicBase(const StorageBasicBase& src);
VTKM_CONT StorageBasicBase& operator=(StorageBasicBase&& src) noexcept;
VTKM_CONT StorageBasicBase& operator=(const StorageBasicBase& src);
/// \brief Return the number of bytes allocated for this storage object(Capacity).
///
///
VTKM_CONT vtkm::UInt64 GetNumberOfBytes() const { return this->AllocatedByteSize; }
/// \brief Return the number of 'T' values allocated by this storage
VTKM_CONT vtkm::Id GetNumberOfValues() const { return this->NumberOfValues; }
/// \brief Allocates an array with the specified number of elements.
///
/// 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 AllocateValues(vtkm::Id numberOfValues, vtkm::UInt64 sizeOfValue);
/// \brief Reduces the size of the array without changing its values.
///
/// This method allows you to resize the array without reallocating it. The
/// size of the array is changed so that it can hold \c numberOfValues values.
/// The data in the reallocated array stays the same, but \c numberOfValues must be
/// equal or less than the preexisting size. That is, this method can only be
/// used to shorten the array, not lengthen.
VTKM_CONT void Shrink(vtkm::Id numberOfValues);
/// \brief Frees any resources (i.e. memory) stored in this array.
///
/// After calling this method GetNumberOfBytes() will return 0. The
/// resources should also be released when the Storage class is
/// destroyed.
VTKM_CONT void ReleaseResources();
/// \brief Returns if vtkm will deallocate this memory. VTK-m StorageBasic
/// is designed that VTK-m will not deallocate user passed memory, or
/// instances that have been stolen (\c StealArray)
VTKM_CONT bool WillDeallocate() const { return this->DeleteFunction != nullptr; }
/// \brief Change the Change the pointer that this class is using. Should only be used
/// by ExecutionArrayInterface sublcasses.
/// Note: This will release any previous allocated memory!
VTKM_CONT void SetBasePointer(const void* ptr,
vtkm::Id numberOfValues,
vtkm::UInt64 sizeOfValue,
void (*deleteFunction)(void*));
/// Return the memory location of the first element of the array data.
VTKM_CONT void* GetBasePointer() const;
VTKM_CONT void* GetEndPointer(vtkm::Id numberOfValues, vtkm::UInt64 sizeOfValue) const;
/// Return the memory location of the first element past the end of the
/// array's allocated memory buffer.
VTKM_CONT void* GetCapacityPointer() const;
protected:
void* Array;
vtkm::UInt64 AllocatedByteSize;
vtkm::Id NumberOfValues;
void (*DeleteFunction)(void*);
};
/// A basic implementation of an Storage object.
///
/// \todo This storage does \em not construct the values within the array.
/// Thus, it is important to not use this class with any type that will fail if
/// not constructed. These are things like basic types (int, float, etc.) and
/// the VTKm Tuple classes. In the future it would be nice to have a compile
/// time check to enforce this.
///
template <typename ValueT>
class VTKM_ALWAYS_EXPORT Storage<ValueT, vtkm::cont::StorageTagBasic> : public StorageBasicBase
{
public:
using AllocatorType = vtkm::cont::internal::StorageBasicAllocator;
using ValueType = ValueT;
using PortalType = vtkm::cont::internal::ArrayPortalFromIterators<ValueType*>;
using PortalConstType = vtkm::cont::internal::ArrayPortalFromIterators<const ValueType*>;
public:
/// \brief construct storage that VTK-m is responsible for
VTKM_CONT Storage();
VTKM_CONT Storage(const Storage<ValueT, vtkm::cont::StorageTagBasic>& src);
VTKM_CONT Storage(Storage<ValueT, vtkm::cont::StorageTagBasic>&& src) noexcept;
/// \brief construct storage that VTK-m is not responsible for
VTKM_CONT Storage(const ValueType* array, vtkm::Id numberOfValues);
/// \brief construct storage that was previously allocated and now VTK-m is
/// responsible for
VTKM_CONT Storage(const ValueType* array, vtkm::Id numberOfValues, void (*deleteFunction)(void*));
VTKM_CONT Storage& operator=(const Storage<ValueT, vtkm::cont::StorageTagBasic>& src);
VTKM_CONT Storage& operator=(Storage<ValueT, vtkm::cont::StorageTagBasic>&& src);
VTKM_CONT void Allocate(vtkm::Id numberOfValues);
VTKM_CONT PortalType GetPortal();
VTKM_CONT PortalConstType GetPortalConst() const;
/// \brief Get a pointer to the underlying data structure.
///
/// This method returns the pointer to the array held by this array. The
/// memory associated with this array still belongs to the Storage (i.e.
/// Storage will eventually deallocate the array).
///
VTKM_CONT ValueType* GetArray();
VTKM_CONT const ValueType* GetArray() const;
/// \brief Transfer ownership of the underlying away from this object.
///
/// This method returns the pointer and free function to the array held
/// by this array. It then clears the internal ownership flags, thereby ensuring
/// that the Storage will never deallocate the array or be able to reallocate it.
/// This is helpful for taking a reference for an array created internally by
/// VTK-m and not having to keep a VTK-m object around. Obviously the caller
/// becomes responsible for destroying the memory, and should use the provided
/// delete function.
///
VTKM_CONT vtkm::Pair<ValueType*, void (*)(void*)> StealArray();
};
} // namespace internal
}
} // namespace vtkm::cont
#ifndef vtkm_cont_StorageBasic_cxx
namespace vtkm
{
namespace cont
{
namespace internal
{
/// \cond
/// Make doxygen ignore this section
#define VTKM_STORAGE_EXPORT(Type) \
extern template class VTKM_CONT_TEMPLATE_EXPORT Storage<Type, StorageTagBasic>; \
extern template class VTKM_CONT_TEMPLATE_EXPORT Storage<vtkm::Vec<Type, 2>, StorageTagBasic>; \
extern template class VTKM_CONT_TEMPLATE_EXPORT Storage<vtkm::Vec<Type, 3>, StorageTagBasic>; \
extern template class VTKM_CONT_TEMPLATE_EXPORT Storage<vtkm::Vec<Type, 4>, StorageTagBasic>;
VTKM_STORAGE_EXPORT(char)
VTKM_STORAGE_EXPORT(vtkm::Int8)
VTKM_STORAGE_EXPORT(vtkm::UInt8)
VTKM_STORAGE_EXPORT(vtkm::Int16)
VTKM_STORAGE_EXPORT(vtkm::UInt16)
VTKM_STORAGE_EXPORT(vtkm::Int32)
VTKM_STORAGE_EXPORT(vtkm::UInt32)
VTKM_STORAGE_EXPORT(vtkm::Int64)
VTKM_STORAGE_EXPORT(vtkm::UInt64)
VTKM_STORAGE_EXPORT(vtkm::Float32)
VTKM_STORAGE_EXPORT(vtkm::Float64)
#undef VTKM_STORAGE_EXPORT
/// \endcond
}
}
}
#endif
#include <vtkm/cont/StorageBasic.hxx>
#endif //vtk_m_cont_StorageBasic_h