Nektar++
NekMemoryManager.hpp
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // File: NekMemoryManager.hpp
4 //
5 // For more information, please see: http://www.nektar.info/
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10 // Department of Aeronautics, Imperial College London (UK), and Scientific
11 // Computing and Imaging Institute, University of Utah (USA).
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a
14 // copy of this software and associated documentation files (the "Software"),
15 // to deal in the Software without restriction, including without limitation
16 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 // and/or sell copies of the Software, and to permit persons to whom the
18 // Software is furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included
21 // in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 // DEALINGS IN THE SOFTWARE.
30 //
31 // Description:
32 //
33 // A memory manager that allocates memory from thread specific pools.
34 //
35 ////////////////////////////////////////////////////////////////////////////////
36 
37 #ifndef NEKTAR_LIB_UTILITIES_NEK_MEMORY_MANAGER_H
38 #define NEKTAR_LIB_UTILITIES_NEK_MEMORY_MANAGER_H
39 
40 #include <memory>
41 #include <type_traits>
42 
43 #include <boost/core/ignore_unused.hpp>
44 
48 
49 #include <vector>
50 
51 #ifdef max
52 #undef max
53 #endif
54 
55 namespace Nektar
56 {
57 
58 /// @brief General purpose memory allocation routines with the ability
59 /// to allocate from thread specific memory pools.
60 ///
61 /// If compiled with NEKTAR_MEMORY_POOL_ENABLED, the MemoryManager
62 /// allocates from thread specific memory pools for small objects.
63 /// Large objects are managed with the system supplied new/delete.
64 /// These memory pools provide faster allocation and deallocation
65 /// of small objects (particularly useful for shared pointers which
66 /// allocate many 4 byte objects).
67 ///
68 /// @warning All memory allocated from the memory manager must be returned
69 /// to the memory manager. Calling delete on memory allocated from the
70 /// manager will likely cause undefined behavior. A particularly subtle
71 /// violation of this rule occurs when giving memory allocated from the
72 /// manager to a shared pointer.
73 /// @code
74 /// std::shared_ptr<Obj> f(MemoryManager<Obj>::Allocate());
75 /// @endcode
76 /// Shared pointers call delete when they go out of scope, so this line of
77 /// code will cause problems. Instead, you should call the
78 /// AllocateSharedPtr method:
79 /// @code
80 /// std::shared_ptr<Obj> f = MemoryManager<Obj>::AllocateSharedPtr();
81 /// @endcode
82 template<typename DataType>
84 {
85 public:
86  /// @brief Deallocate a pointer allocated by
87  /// MemoryManager::Allocate.
88  /// @note Results are undefined if called with a pointer to
89  /// something that was not allocated with the memory manager.
90  ///
91  /// Use this method to deallocate a pointer you have allocated from
92  /// the MemoryManager using the Allocate method.
93  ///
94  /// Example:
95  /// @code
96  /// CustObj* c = MemoryManager::Allocate<CustObj>();
97  /// MemoryManager::Deallocate(c);
98  /// @endcode
99  static void Deallocate(DataType*& data)
100  {
101 #ifdef NEKTAR_MEMORY_POOL_ENABLED
102  data->~DataType();
103  GetMemoryPool().Deallocate(data, sizeof(DataType));
104 #else
105  delete data;
106 #endif
107 
108  data = NULL;
109  }
110 
111 #ifdef NEKTAR_MEMORY_POOL_ENABLED
112  /// @brief Allocates a single object from the memory pool.
113  /// @throws unknown If the object throws an exception during
114  /// construction, this method will catch it, release the memory
115  /// back to the pool, then rethrow it.
116  ///
117  /// The allocated object must be returned to the memory pool
118  /// via Deallocate.
119  template<typename... Args>
120  static DataType* Allocate(const Args &...args)
121  {
122  DataType* result = static_cast<DataType*>(
123  GetMemoryPool().Allocate(sizeof(DataType)));
124 
125  if (result)
126  {
127  try
128  {
129  new (result) DataType(args...);
130  }
131  catch(...)
132  {
133  GetMemoryPool().Deallocate(result, sizeof(DataType));
134  throw;
135  }
136  }
137 
138  return result;
139  }
140 
141 #else //NEKTAR_MEMORY_POOL_ENABLED
142  /// @brief Allocates a single object from the memory pool.
143  /// @throws unknown Any exception thrown by DataType's default
144  /// constructor will propogate through this method.
145  ///
146  /// The allocated object must be returned to the memory pool
147  /// via Deallocate.
148  template<typename... Args>
149  static DataType* Allocate(const Args &...args)
150  {
151  return new DataType(args...);
152  }
153 #endif //NEKTAR_MEMORY_POOL_ENABLED
154 
155  /// @brief Allocate a shared pointer from the memory pool.
156  ///
157  /// The shared pointer does not need to be returned to the memory
158  /// pool. When the reference count to this object reaches 0, the
159  /// shared pointer will automatically return the memory.
160  template<typename... Args>
161  static std::shared_ptr<DataType> AllocateSharedPtr(const Args &...args)
162  {
163  return AllocateSharedPtrD( [](DataType *){}, args...);
164  }
165 
166  template<typename DeallocatorType, typename... Args>
167  static std::shared_ptr<DataType> AllocateSharedPtrD(
168  const DeallocatorType& d, const Args &...args)
169  {
170  DataType* data = Allocate(args...);
171  return std::shared_ptr<DataType>(
172  data, [=](DataType *ptr){
173  d(ptr);
175  });
176  }
177 
178  /// \brief Allocates a chunk of raw, uninitialized memory, capable of
179  /// holding NumberOfElements objects.
180  ///
181  /// \param NumberOfElements The number of elements the array should be
182  /// capable of holding.
183  ///
184  /// This method is not meant to be called by client code. Use Array
185  /// instead. Any memory allocated from this method must be returned to the
186  /// memory pool via RawDeallocate. Failure to do so will result in memory
187  /// leaks and undefined behavior.
188  static DataType* RawAllocate(size_t NumberOfElements)
189  {
190 #ifdef NEKTAR_MEMORY_POOL_ENABLED
191  return static_cast<DataType*>(GetMemoryPool().Allocate(sizeof(DataType)*NumberOfElements));
192 #else //NEKTAR_MEMORY_POOL_ENABLED
193  return static_cast<DataType*>(::operator new(NumberOfElements * sizeof(DataType)));
194 #endif //NEKTAR_MEMORY_POOL_ENABLED
195  }
196 
197 
198  /// \brief Deallocates memory allocated from RawAllocate.
199  /// \param array A pointer to the memory returned from RawAllocate.
200  /// \param NumberOfElements The number of object held in the array.
201  ///
202  /// This method is not meant to be called by client code. Use Array instead.
203  /// Only memory allocated via RawAllocate should be returned to the pool here.
204  static void RawDeallocate(DataType* array, size_t NumberOfElements)
205  {
206 #ifdef NEKTAR_MEMORY_POOL_ENABLED
207  GetMemoryPool().Deallocate(array, sizeof(DataType)*NumberOfElements);
208 #else //NEKTAR_MEMORY_POOL_ENABLED
209  ::operator delete(array);
210 #endif //NEKTAR_MEMORY_POOL_ENABLED
211  }
212 
213  /////////////////////////////////////////////////////////////////
214  ///\name Allocator Interface
215  /// The allocator interface allows a MemoryManager object to be used
216  /// in any object that allows an allocator parameter, such as STL
217  /// containers.
218  /////////////////////////////////////////////////////////////////
219  typedef DataType value_type;
220  typedef size_t size_type;
221  typedef ptrdiff_t difference_type;
222  typedef DataType* pointer;
223  typedef const DataType* const_pointer;
224  typedef DataType& reference;
225  typedef const DataType& const_reference;
226 
228  template<typename T>
230  {
231  boost::ignore_unused(rhs);
232  }
234 
235  pointer address(reference r) const { return &r; }
236  const_pointer address(const_reference r) const { return &r; }
237 
238  pointer allocate(size_type n, std::allocator<void>::const_pointer hint = 0)//typename MemoryManager<void>::pointer hint = 0)
239  {
240  boost::ignore_unused(hint);
241  return RawAllocate(n);
242  }
243 
244  void deallocate(pointer p, size_type n)
245  {
246  return RawDeallocate(p, n);
247  }
248 
249  void construct(pointer p, const_reference val)
250  {
251  new(p) DataType(val);
252  }
253 
254  void destroy(pointer p)
255  {
256  p->~DataType();
257  }
258 
259  size_type max_size()
260  {
261  return std::numeric_limits<size_type>::max()/sizeof(DataType);
262  }
263 
264  template<typename U>
265  struct rebind
266  {
268  };
269 
270  /////////////////////////////////////////////////////////////////
271  ///@}
272  /////////////////////////////////////////////////////////////////
273 
274 private:
275 
276 };
277 
278 template<typename DataType>
280 {
281  boost::ignore_unused(lhs,rhs);
282  return true;
283 }
284 
285 template<typename DataType>
287 {
288  return !(lhs == rhs);
289 }
290 
291 }
292 
293 #endif //NEKTAR_LIB_UTILITIES_NEK_MEMORY_MANAGER_H
294 
295 
static std::shared_ptr< DataType > AllocateSharedPtrD(const DeallocatorType &d, const Args &...args)
General purpose memory allocation routines with the ability to allocate from thread specific memory p...
static void RawDeallocate(DataType *array, size_t NumberOfElements)
Deallocates memory allocated from RawAllocate.
static DataType * RawAllocate(size_t NumberOfElements)
Allocates a chunk of raw, uninitialized memory, capable of holding NumberOfElements objects...
void Deallocate(void *p, size_t bytes)
Deallocate memory claimed by an earlier call to allocate.
bool operator==(const Array< OneD, NekDouble > &lhs, const Array< OneD, NekDouble > &rhs)
const DataType * const_pointer
StandardMatrixTag & lhs
void * Allocate(size_t bytes)
Allocate a block of memory of size ByteSize.
void deallocate(pointer p, size_type n)
bool operator!=(const Array< OneD, T1 > &lhs, const Array< OneD, T2 > &rhs)
pointer allocate(size_type n, std::allocator< void >::const_pointer hint=0)
void construct(pointer p, const_reference val)
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
MemPool & GetMemoryPool()
const DataType & const_reference
MemoryManager(const MemoryManager< T > &rhs)
static void Deallocate(DataType *&data)
Deallocate a pointer allocated by MemoryManager::Allocate.
static DataType * Allocate(const Args &...args)
Allocates a single object from the memory pool.
const_pointer address(const_reference r) const
StandardMatrixTag boost::call_traits< LhsDataType >::const_reference rhs
pointer address(reference r) const