StorageBasic.h 7.05 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
//============================================================================
//  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 Sandia Corporation.
//  Copyright 2014 UT-Battelle, LLC.
11
//  Copyright 2014 Los Alamos National Security.
12 13 14 15 16 17 18 19
//
//  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
//  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.
//============================================================================
20 21
#ifndef vtk_m_cont_StorageBasic_h
#define vtk_m_cont_StorageBasic_h
22 23 24 25 26

#include <vtkm/Types.h>
#include <vtkm/cont/Assert.h>
#include <vtkm/cont/ErrorControlBadValue.h>
#include <vtkm/cont/ErrorControlOutOfMemory.h>
27 28
#include <vtkm/cont/Storage.h>

29 30 31 32 33
#include <vtkm/cont/internal/ArrayPortalFromIterators.h>

namespace vtkm {
namespace cont {

34 35
/// A tag for the basic implementation of a Storage object.
struct StorageTagBasic {  };
36 37 38

namespace internal {

39
/// A basic implementation of an Storage object.
40
///
41
/// \todo This storage does \em not construct the values within the array.
42 43 44 45 46 47
/// 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>
48
class Storage<ValueT, vtkm::cont::StorageTagBasic>
49 50 51 52 53 54 55 56
{
public:
  typedef ValueT ValueType;
  typedef vtkm::cont::internal::ArrayPortalFromIterators<ValueType*> PortalType;
  typedef vtkm::cont::internal::ArrayPortalFromIterators<const ValueType*> PortalConstType;

  /// The original design of this class provided an allocator as a template
  /// parameters. That messed things up, though, because other templated
57 58 59 60
  /// classes assume that the \c Storage has one template parameter. There are
  /// other ways to allow you to specify the allocator, but it is uncertain
  /// whether that would ever be useful. So, instead of jumping through hoops
  /// implementing them, just fix the allocator for now.
61 62 63 64 65
  ///
  typedef std::allocator<ValueType> AllocatorType;

public:

66 67 68 69 70 71 72 73 74
  VTKM_CONT_EXPORT
  Storage(const ValueType *array = NULL, vtkm::Id numberOfValues = 0)
    : Array(const_cast<ValueType *>(array)),
      NumberOfValues(numberOfValues),
      AllocatedSize(numberOfValues),
      DeallocateOnRelease(false),
      ReadOnly(true) { }

  VTKM_CONT_EXPORT
75
  ~Storage()
76 77 78 79
  {
    this->ReleaseResources();
  }

80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
  VTKM_CONT_EXPORT
  Storage(const Storage<ValueType, StorageTagBasic> &src)
    : Array(src.Array),
      NumberOfValues(src.NumberOfValues),
      AllocatedSize(src.AllocatedSize),
      DeallocateOnRelease(false),
      ReadOnly(src.ReadOnly)
  {
    if (src.DeallocateOnRelease)
    {
      throw vtkm::cont::ErrorControlBadValue(
            "Attempted to copy a storage array that needs deallocation. "
            "This is disallowed to prevent complications with deallocation.");
    }
  }

  VTKM_CONT_EXPORT
  Storage &operator=(const Storage<ValueType, StorageTagBasic> &src)
  {
    if (src.DeallocateOnRelease)
    {
      throw vtkm::cont::ErrorControlBadValue(
            "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;
    this->ReadOnly = src.ReadOnly;

    return *this;
  }

  VTKM_CONT_EXPORT
117 118 119
  void ReleaseResources()
  {
    if (this->NumberOfValues > 0)
120
    {
121
      VTKM_ASSERT_CONT(this->Array != NULL);
122 123 124 125 126
      if (this->DeallocateOnRelease)
      {
        AllocatorType allocator;
        allocator.deallocate(this->Array, this->AllocatedSize);
      }
127 128 129
      this->Array = NULL;
      this->NumberOfValues = 0;
      this->AllocatedSize = 0;
130
    }
131
    else
132
    {
133
      VTKM_ASSERT_CONT(this->Array == NULL);
134
    }
135 136
  }

137
  VTKM_CONT_EXPORT
138 139
  void Allocate(vtkm::Id numberOfValues)
  {
140 141
    if ((numberOfValues <= this->AllocatedSize)
        && !this->ReadOnly)
142
    {
143 144
      this->NumberOfValues = numberOfValues;
      return;
145
    }
146 147 148

    this->ReleaseResources();
    try
149
    {
150
      if (numberOfValues > 0)
151
      {
152 153 154 155
        AllocatorType allocator;
        this->Array = allocator.allocate(numberOfValues);
        this->AllocatedSize  = numberOfValues;
        this->NumberOfValues = numberOfValues;
156
      }
157
      else
158
      {
159 160 161
        // ReleaseResources should have already set AllocatedSize to 0.
        VTKM_ASSERT_CONT(this->AllocatedSize == 0);
      }
162
    }
163
    catch (std::bad_alloc err)
164
    {
165 166 167 168 169
      // Make sureour state is OK.
      this->Array = NULL;
      this->NumberOfValues = 0;
      this->AllocatedSize = 0;
      throw vtkm::cont::ErrorControlOutOfMemory(
170 171
        "Could not allocate basic control array.");
    }
172 173 174

    this->DeallocateOnRelease = true;
    this->ReadOnly = false;
175 176
  }

177
  VTKM_CONT_EXPORT
178 179 180 181 182
  vtkm::Id GetNumberOfValues() const
  {
    return this->NumberOfValues;
  }

183
  VTKM_CONT_EXPORT
184 185
  void Shrink(vtkm::Id numberOfValues)
  {
186 187 188 189 190
    if (this->ReadOnly)
    {
      throw vtkm::cont::ErrorControlBadValue("Cannot shrink read-only array.");
    }

191
    if (numberOfValues > this->GetNumberOfValues())
192
    {
193
      throw vtkm::cont::ErrorControlBadValue(
194 195
        "Shrink method cannot be used to grow array.");
    }
196 197 198 199

    this->NumberOfValues = numberOfValues;
  }

200
  VTKM_CONT_EXPORT
201 202
  PortalType GetPortal()
  {
203 204 205 206 207
    if (this->ReadOnly)
    {
      throw vtkm::cont::ErrorControlBadValue(
            "Tried to access read-only array as read-write.");
    }
208 209 210
    return PortalType(this->Array, this->Array + this->NumberOfValues);
  }

211
  VTKM_CONT_EXPORT
212 213 214 215 216 217 218 219 220
  PortalConstType GetPortalConst() const
  {
    return PortalConstType(this->Array, this->Array + this->NumberOfValues);
  }

  /// \brief Take the reference away from this object.
  ///
  /// This method returns the pointer to the array held by this array. It then
  /// clears the internal array pointer to NULL, thereby ensuring that the
221 222 223 224
  /// Storage will never deallocate the array. 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.
225
  ///
226
  VTKM_CONT_EXPORT
227 228 229 230 231 232 233 234 235 236 237 238 239
  ValueType *StealArray()
  {
    ValueType *saveArray =  this->Array;
    this->Array = NULL;
    this->NumberOfValues = 0;
    this->AllocatedSize = 0;
    return saveArray;
  }

private:
  ValueType *Array;
  vtkm::Id NumberOfValues;
  vtkm::Id AllocatedSize;
240 241
  bool DeallocateOnRelease;
  bool ReadOnly;
242 243 244 245 246 247 248
};

} // namespace internal

}
} // namespace vtkm::cont

249
#endif //vtk_m_cont_StorageBasic_h