//============================================================================ // Copyright (c) Kitware, Inc. // All rights reserved. // See LICENSE.txt for details. // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notice for more information. // // Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS). // Copyright 2014 UT-Battelle, LLC. // Copyright 2014 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. //============================================================================ #include #include namespace vtkm { namespace cont { namespace internal { template Storage::Storage() : Array(nullptr) , NumberOfValues(0) , AllocatedSize(0) , DeallocateOnRelease(true) { } template Storage::Storage(const T* array, vtkm::Id numberOfValues) : Array(const_cast(array)) , NumberOfValues(numberOfValues) , AllocatedSize(numberOfValues) , DeallocateOnRelease(array == nullptr ? true : false) { } template Storage::~Storage() { this->ReleaseResources(); } template Storage::Storage(const Storage& src) : Array(src.Array) , NumberOfValues(src.NumberOfValues) , AllocatedSize(src.AllocatedSize) , DeallocateOnRelease(src.DeallocateOnRelease) { if (src.DeallocateOnRelease) { throw vtkm::cont::ErrorBadValue( "Attempted to copy a storage array that needs deallocation. " "This is disallowed to prevent complications with deallocation."); } } template Storage& Storage::operator=( const Storage& src) { if (src.DeallocateOnRelease) { throw vtkm::cont::ErrorBadValue( "Attempted to copy a storage array that needs deallocation. " "This is disallowed to prevent complications with deallocation."); } this->ReleaseResources(); this->Array = src.Array; this->NumberOfValues = src.NumberOfValues; this->AllocatedSize = src.AllocatedSize; this->DeallocateOnRelease = src.DeallocateOnRelease; return *this; } template void Storage::ReleaseResources() { if (this->NumberOfValues > 0) { VTKM_ASSERT(this->Array != nullptr); if (this->DeallocateOnRelease) { AllocatorType allocator; allocator.deallocate(this->Array, static_cast(this->AllocatedSize)); } this->Array = nullptr; this->NumberOfValues = 0; this->AllocatedSize = 0; } else { VTKM_ASSERT(this->Array == nullptr); } } template void Storage::Allocate(vtkm::Id numberOfValues) { if (numberOfValues < 0) { throw vtkm::cont::ErrorBadAllocation("Cannot allocate an array with negative size."); } // Check that the number of bytes won't be more than a size_t can hold. const size_t maxNumValues = std::numeric_limits::max() / sizeof(T); if (static_cast(numberOfValues) > static_cast(maxNumValues)) { throw ErrorBadAllocation("Requested allocation exceeds size_t capacity."); } this->AllocateBytes(static_cast(numberOfValues) * static_cast(sizeof(T))); } template void Storage::AllocateBytes(vtkm::UInt64 numberOfBytes) { const vtkm::Id numberOfValues = static_cast(numberOfBytes / static_cast(sizeof(T))); // If we are allocating less data, just shrink the array. // (If allocation empty, drop down so we can deallocate memory.) if ((numberOfValues <= this->AllocatedSize) && (numberOfValues > 0)) { this->NumberOfValues = numberOfValues; return; } if (!this->DeallocateOnRelease) { throw vtkm::cont::ErrorBadValue("User allocated arrays cannot be reallocated."); } this->ReleaseResources(); try { if (numberOfValues > 0) { AllocatorType allocator; this->Array = allocator.allocate(static_cast(numberOfValues)); this->AllocatedSize = numberOfValues; this->NumberOfValues = numberOfValues; } else { // ReleaseResources should have already set AllocatedSize to 0. VTKM_ASSERT(this->AllocatedSize == 0); } } catch (std::bad_alloc&) { // Make sureour state is OK. this->Array = nullptr; this->NumberOfValues = 0; this->AllocatedSize = 0; throw vtkm::cont::ErrorBadAllocation("Could not allocate basic control array."); } this->DeallocateOnRelease = true; } template void Storage::Shrink(vtkm::Id numberOfValues) { this->ShrinkBytes(static_cast(numberOfValues) * static_cast(sizeof(T))); } template void Storage::ShrinkBytes(vtkm::UInt64 numberOfBytes) { if (numberOfBytes > this->GetNumberOfBytes()) { throw vtkm::cont::ErrorBadValue("Shrink method cannot be used to grow array."); } this->NumberOfValues = static_cast(numberOfBytes / static_cast(sizeof(T))); } template T* Storage::StealArray() { this->DeallocateOnRelease = false; return this->Array; } } // namespace internal } } // namespace vtkm::cont