TPIE

v1.1rc1-6-g0c97303
memory.h
Go to the documentation of this file.
1 // -*- mode: c++; tab-width: 4; indent-tabs-mode: t; eval: (progn (c-set-style "stroustrup") (c-set-offset 'innamespace 0)); -*-
2 // vi:set ts=4 sts=4 sw=4 noet :
3 //
4 // Copyright 2011, The TPIE development team
5 //
6 // This file is part of TPIE.
7 //
8 // TPIE is free software: you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License as published by the
10 // Free Software Foundation, either version 3 of the License, or (at your
11 // option) any later version.
12 //
13 // TPIE is distributed in the hope that it will be useful, but WITHOUT ANY
14 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16 // License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public License
19 // along with TPIE. If not, see <http://www.gnu.org/licenses/>
20 
24 
25 #ifndef __TPIE_MEMORY_H__
26 #define __TPIE_MEMORY_H__
27 
28 #include <tpie/config.h>
29 #include <tpie/util.h>
30 #include <boost/thread/mutex.hpp>
31 #include <boost/unordered_map.hpp>
32 #include <boost/type_traits/is_polymorphic.hpp>
33 #include <utility>
34 #include <fstream>
35 
36 namespace tpie {
37 
38 namespace bits {
39  class atomic_int;
40 }
41 
48 struct out_of_memory_error : public std::bad_alloc {
49  const char * msg;
50  out_of_memory_error(const char * s) : msg(s) { }
51  virtual const char* what() const throw() {return msg;}
52 };
53 
54 
59 public:
63  enum enforce_t {
74  };
75 
79  size_t used() const throw();
80 
84  size_t available() const throw();
85 
89  inline size_t limit() const throw() {return m_limit;}
90 
97  void set_limit(size_t new_limit);
98 
103  void set_enforcement(enforce_t e);
104 
108  inline enforce_t enforcement() {return m_enforce;}
109 
116  void register_allocation(size_t bytes);
117 
122  void register_deallocation(size_t bytes);
123 
128  memory_manager();
129 
134  std::pair<uint8_t *, size_t> __allocate_consecutive(size_t upper_bound, size_t granularity);
135 
136 #ifndef TPIE_NDEBUG
137  // The following methods take the mutex before calling the private doubly
138  // underscored equivalent.
139  void register_pointer(void * p, size_t size, const std::type_info & t);
140  void unregister_pointer(void * p, size_t size, const std::type_info & t);
141  void assert_tpie_ptr(void * p);
142  void complain_about_unfreed_memory();
143 #endif
144 
145 
146 private:
147  std::auto_ptr<bits::atomic_int> m_used;
148  size_t m_limit;
149  size_t m_maxExceeded;
150  size_t m_nextWarning;
151  enforce_t m_enforce;
152 
153 #ifndef TPIE_NDEBUG
154  boost::mutex m_mutex;
155 
156  // Before calling these methods, you must have the mutex.
157  void __register_pointer(void * p, size_t size, const std::type_info & t);
158  void __unregister_pointer(void * p, size_t size, const std::type_info & t);
159  void __assert_tpie_ptr(void * p);
160  void __complain_about_unfreed_memory();
161 
162  boost::unordered_map<void *, std::pair<size_t, const std::type_info *> > m_pointers;
163 #endif
164 };
165 
169 void init_memory_manager();
170 
174 void finish_memory_manager();
175 
181 memory_manager & get_memory_manager();
182 
187 inline void __register_pointer(void * p, size_t size, const std::type_info & t) {
188 #ifndef TPIE_NDEBUG
189  get_memory_manager().register_pointer(p, size, t);
190 #else
191  unused(p);
192  unused(size);
193  unused(t);
194 #endif
195 }
196 
201 inline void __unregister_pointer(void * p, size_t size, const std::type_info & t) {
202 #ifndef TPIE_NDEBUG
203  get_memory_manager().unregister_pointer(p, size, t);
204 #else
205  unused(p);
206  unused(size);
207  unused(t);
208 #endif
209 }
210 
215 inline void assert_tpie_ptr(void * p) {
216 #ifndef TPIE_NDEBUG
217  if (p)
218  get_memory_manager().assert_tpie_ptr(p);
219 #else
220  unused(p);
221 #endif
222 }
223 
224 #ifndef DOXYGEN
225 template <typename T, bool x=boost::is_polymorphic<T>::value >
229 struct __object_addr {
230  inline void * operator()(T * o) {return static_cast<void *>(o);}
231 };
232 
236 template <typename T>
237 struct __object_addr<T, true> {
238  inline void * operator()(T * o) {return dynamic_cast<void *>(o);}
239 };
240 #endif
241 
249 template <typename D, typename T>
250 inline D ptr_cast(T * t) { return reinterpret_cast<D>(__object_addr<T>()(t)); }
251 
252 
253 template <typename T>
254 inline T * __allocate() {
255  if(!boost::is_polymorphic<T>::value) return reinterpret_cast<T *>(new uint8_t[sizeof(T)]);
256  uint8_t * x = new uint8_t[sizeof(T)+sizeof(size_t)];
257  *reinterpret_cast<size_t*>(x) = sizeof(T);
258  return reinterpret_cast<T*>(x + sizeof(size_t));
259 }
260 
261 template <typename T>
262 inline size_t tpie_size(T * p) {
263  if(!boost::is_polymorphic<T>::value) return sizeof(T);
264  uint8_t * x = ptr_cast<uint8_t *>(p);
265  return * reinterpret_cast<size_t *>(x - sizeof(size_t));
266 }
267 
268 
273 template <typename T>
275  size_t size;
276  T * data;
277  inline array_allocation_scope_magic(size_t s): size(0), data(0) {
278  get_memory_manager().register_allocation(s * sizeof(T) );
279  size=s;
280  }
281 
282  inline T * allocate() {
283  data = new T[size];
284  __register_pointer(data, size*sizeof(T), typeid(T));
285  return data;
286  }
287 
288  T * finalize() {
289  T * d = data;
290  size = 0;
291  data = 0;
292  return d;
293  }
294 
295  inline ~array_allocation_scope_magic() {
296  if(size) get_memory_manager().register_deallocation(size*sizeof(T));
297  }
298 };
299 
304 template <typename T>
306  size_t deregister;
307  T * data;
308  inline allocation_scope_magic(): deregister(0), data(0) {}
309 
310  inline T * allocate() {
312  deregister = sizeof(T);
313  data = __allocate<T>();
314  __register_pointer(data, sizeof(T), typeid(T));
315  return data;
316  }
317 
318  T * finalize() {
319  T * d = data;
320  deregister = 0;
321  data = 0;
322  return d;
323  }
324 
325  inline ~allocation_scope_magic() {
326  if (data) __unregister_pointer(data, sizeof(T), typeid(T));
327  delete[] reinterpret_cast<uint8_t*>(data);
328  if (deregister) get_memory_manager().register_deallocation(deregister);
329  }
330 };
331 
337 template <typename T>
338 inline T * tpie_new_array(size_t size) {
340  m.allocate();
341  return m.finalize();
342 }
343 
344 
345 #ifdef DOXYGEN
346 template <typename T, typename Args>
360 inline T * tpie_new(Args args);
361 
362 #elif defined(TPIE_CPP_VARIADIC_TEMPLATES) && defined(TPIE_CPP_RVALUE_REFERENCE)
363 
364 template <typename T, typename ... Args>
365 inline T * tpie_new(Args &&... args) {
366  allocation_scope_magic<T> m;
367  new(m.allocate()) T(std::forward<Args>(args)...);
368  return m.finalize();
369 }
370 
371 #else
372 #include <tpie/memory.inl>
373 #endif
374 
379 template <typename T>
380 inline void tpie_delete(T * p) throw() {
381  if (p == 0) return;
383  uint8_t * pp = ptr_cast<uint8_t *>(p);
384  __unregister_pointer(pp, tpie_size(p), typeid(*p));
385  p->~T();
386  if(!boost::is_polymorphic<T>::value)
387  delete[] pp;
388  else
389  delete[] (pp - sizeof(size_t));
390 }
391 
397 template <typename T>
398 inline void tpie_delete_array(T * a, size_t size) throw() {
399  if (a == 0) return;
400  get_memory_manager().register_deallocation(sizeof(T) * size);
401  __unregister_pointer(a, sizeof(T) * size, typeid(T) );
402  delete[] a;
403 }
404 
405 template <typename T>
406 struct auto_ptr_ref {
407  T * m_ptr;
408  explicit inline auto_ptr_ref(T * ptr) throw(): m_ptr(ptr) {};
409 };
410 
415 template <typename T>
416 class auto_ptr {
417 private:
418  T * elm;
419  // auto_ptr(const auto_ptr & o) {unused(o); assert(false);}
420  // auto_ptr & operator = (const auto_ptr & o) {unused(o); assert(false);}
421 public:
422  typedef T element_type;
423 
424  // D.10.1.1 construct/copy/destroy:
425  explicit inline auto_ptr(T * o=0) throw(): elm(0){reset(o);}
426  inline auto_ptr(auto_ptr & o) throw(): elm(0) {reset(o.release());}
427  template <class Y>
428  inline auto_ptr(auto_ptr<Y> & o) throw(): elm(0) {reset(o.release());}
429 
430  inline auto_ptr & operator =(auto_ptr & o) throw() {reset(o.release()); return *this;}
431  template <class Y>
432  inline auto_ptr & operator =(auto_ptr<Y> & o) throw() {reset(o.release()); return *this;}
433  inline auto_ptr & operator =(auto_ptr_ref<T> r) throw() {reset(r.m_ptr); return *this;}
434 
435  inline ~auto_ptr() throw() {reset();}
436 
437  // D.10.1.2 members:
438  inline T & operator*() const throw() {return *elm;}
439  inline T * operator->() const throw() {return elm;}
440  inline T * get() const throw() {return elm;}
441  inline T * release() throw () {T * t=elm; elm=0; return t;}
442  inline void reset(T * o=0) throw () {
443  if (o == elm) return;
444  tpie_delete<T>(elm);
445  assert_tpie_ptr(o);
446  elm=o;
447  }
448 
449  // D.10.1.3 conversions:
450  inline auto_ptr(auto_ptr_ref<T> r) throw(): elm(0) {reset(r.m_ptr);}
451 
452  template <class Y>
453  inline operator auto_ptr_ref<Y>() throw() {return auto_ptr_ref<Y>(release());}
454 
455  template<class Y>
456  inline operator auto_ptr<Y>() throw() {return auto_ptr<Y>(release());}
457 };
458 
464 template <class T>
465 class allocator {
466 private:
467  typedef std::allocator<T> a_t;
468  a_t a;
469 public:
470  typedef typename a_t::size_type size_type;
471  typedef typename a_t::difference_type difference_type;
472  typedef typename a_t::pointer pointer;
473  typedef typename a_t::const_pointer const_pointer;
474  typedef typename a_t::reference reference;
475  typedef typename a_t::const_reference const_reference;
476  typedef typename a_t::value_type value_type;
477 
478  allocator() throw() {}
479  allocator(const allocator & a) throw() {unused(a);}
480  template <typename T2>
481  allocator(const allocator<T2> & a) throw() {unused(a);}
482 
483  template <class U> struct rebind {typedef allocator<U> other;};
484 
485  inline T * allocate(size_t size, const void * hint=0) {
486  get_memory_manager().register_allocation(size * sizeof(T));
487  T * res = a.allocate(size, hint);
488  __register_pointer(res, size, typeid(T));
489  return res;
490  }
491 
492  inline void deallocate(T * p, size_t n) {
493  if (p == 0) return;
494  __unregister_pointer(p, n, typeid(T));
495  get_memory_manager().register_deallocation(n * sizeof(T));
496  return a.deallocate(p, n);
497  }
498  inline size_t max_size() const {return a.max_size();}
499 
500 #ifdef TPIE_CPP_RVALUE_REFERENCE
501 #ifdef TPIE_CPP_VARIADIC_TEMPLATES
502  template <typename ...TT>
503  inline void construct(T * p, TT &&...x) {a.construct(p, x...);}
504 #else
505  #ifdef __clang__
506  //push the current warning state
507  #pragma clang diagnostic push
508  //disable warning about "rvalue references are a C++11 extension
509  #pragma clang diagnostic ignored "-Wc++11-extensions"
510  #endif
511  template <typename TT>
512  inline void construct(T * p, TT && val) {a.construct(p, val);}
513  #ifdef __clang__
514  //restore the warning state
515  #pragma clang diagnostic pop
516  #endif
517 #endif
518 #endif
519  inline void construct(T * p) {
520 #ifdef WIN32
521 #pragma warning( push )
522 #pragma warning(disable: 4345)
523 #endif
524  new(p) T();
525 #ifdef WIN32
526 #pragma warning( pop )
527 #endif
528  }
529  inline void construct(T * p, const T& val) {a.construct(p, val);}
530  inline void destroy(T * p) {a.destroy(p);}
531  inline pointer address(reference x) const {return &x;}
532  inline const_pointer address(const_reference x) const {return &x;}
533 };
534 
535 template <typename T>
536 inline bool operator==(const tpie::allocator<T>&, const tpie::allocator<T>&) {return true;}
537 
538 template<typename T>
539 inline bool operator!=(const tpie::allocator<T>&, const tpie::allocator<T>&) {return false;}
540 
541 
546 size_t consecutive_memory_available(size_t granularity=5*1024*1024);
547 
548 } //namespace tpie
549 
550 namespace std {
551 template <typename T>
552 void swap(tpie::auto_ptr<T> & a, tpie::auto_ptr<T> & b) {
553  T * t =a.release();
554  a.reset(b.release());
555  b.reset(t);
556 }
557 } //namespace std
558 
559 #endif //__TPIE_MEMORY_H__
size_t limit() const
Return the memory limit.
Definition: memory.h:89
size_t consecutive_memory_available(size_t granularity=5 *1024 *1024)
Find the largest amount of memory that can be allocated as a single chunk.
enforce_t
Memory limit enforcement policies.
Definition: memory.h:63
void __register_pointer(void *p, size_t size, const std::type_info &t)
Definition: memory.h:187
Ignore when running out of memory.
Definition: memory.h:65
Throw an out_of_memory_error when the memory limit is exceeded.
Definition: memory.h:73
void unused(const T &x)
Declare that a variable is unused on purpose.
Definition: util.h:42
Log to debug log when the memory limit is exceeded.
Definition: memory.h:68
void __unregister_pointer(void *p, size_t size, const std::type_info &t)
Definition: memory.h:201
size_t available() const
Return the amount of memory still available to allocation.
enforce_t enforcement()
Return the current memory limit enforcement policy.
Definition: memory.h:108
T * tpie_new_array(size_t size)
Allocate a new array and register its memory usage.
Definition: memory.h:338
void register_deallocation(size_t bytes)
A allocator object usable in STL containers, using the TPIE memory manager.
Definition: memory.h:465
memory_manager & get_memory_manager()
Return a reference to the memory manager.
Miscellaneous utility functions.
void finish_memory_manager()
Used by tpie_finish to deinitialize the memory manager.
Log a warning when the memory limit is exceeded.
Definition: memory.h:71
Memory management object used to track memory usage.
Definition: memory.h:58
size_t used() const
Return the current amount of memory used.
void tpie_delete(T *p)
Delete an object allocated with tpie_new.
Definition: memory.h:380
like std::auto_ptr, but delete the object with tpie_delete.
Definition: memory.h:416
void register_allocation(size_t bytes)
void assert_tpie_ptr(void *p)
In a debug build, assert that a given pointer has been allocated with tpie_new.
Definition: memory.h:215
std::pair< uint8_t *, size_t > __allocate_consecutive(size_t upper_bound, size_t granularity)
Thrown when trying to allocate too much memory.
Definition: memory.h:48
void init_memory_manager()
Used by tpie_init to initialize the memory manager.
void set_limit(size_t new_limit)
Update the memory limit.
T * tpie_new(Args args)
Allocate an element of the type given as template parameter, and register its memory usage with TPIE...
void set_enforcement(enforce_t e)
Set the memory limit enforcement policy.
void tpie_delete_array(T *a, size_t size)
Delete an array allocated with tpie_new_array.
Definition: memory.h:398
D ptr_cast(T *t)
Cast between pointer types.
Definition: memory.h:250