Thrill  0.1
allocator.hpp
Go to the documentation of this file.
1 /*******************************************************************************
2  * thrill/mem/allocator.hpp
3  *
4  * Part of Project Thrill - http://project-thrill.org
5  *
6  * Copyright (C) 2015 Timo Bingmann <[email protected]>
7  *
8  * All rights reserved. Published under the BSD-2 license in the LICENSE file.
9  ******************************************************************************/
10 
11 #pragma once
12 #ifndef THRILL_MEM_ALLOCATOR_HEADER
13 #define THRILL_MEM_ALLOCATOR_HEADER
14 
16 #include <thrill/mem/manager.hpp>
17 
18 #include <cassert>
19 #include <deque>
20 #include <iosfwd>
21 #include <memory>
22 #include <new>
23 #include <string>
24 #include <type_traits>
25 #include <vector>
26 
27 namespace thrill {
28 namespace mem {
29 
30 template <typename Type>
31 class Allocator : public tlx::AllocatorBase<Type>
32 {
33  static constexpr bool debug = false;
34 
35 public:
36  using value_type = Type;
37  using pointer = Type *;
38  using const_pointer = const Type *;
39  using reference = Type&;
40  using const_reference = const Type&;
41  using size_type = std::size_t;
42  using difference_type = std::ptrdiff_t;
43 
44  //! C++11 type flag
45  using is_always_equal = std::false_type;
46 
47  //! Return allocator for different type.
48  template <typename U>
49  struct rebind { using other = Allocator<U>; };
50 
51  //! Construct Allocator with Manager object
52  explicit Allocator(Manager& manager) noexcept
53  : manager_(&manager) { }
54 
55  //! copy-constructor
56  Allocator(const Allocator&) noexcept = default;
57 
58  //! copy-constructor from a rebound allocator
59  template <typename OtherType>
61  : manager_(other.manager_) { }
62 
63  //! copy-assignment operator
64  Allocator& operator = (const Allocator&) noexcept = default;
65 
66  //! Attempts to allocate a block of storage with a size large enough to
67  //! contain n elements of member type value_type, and returns a pointer to
68  //! the first element.
69  pointer allocate(size_type n, const void* /* hint */ = nullptr) {
70  if (n > this->max_size())
71  throw std::bad_alloc();
72 
73  const size_t size = n * sizeof(Type);
74  manager_->add(size);
75 
76  if (debug) {
77  printf("allocate() n=%zu sizeof(T)=%zu total=%zu\n",
78  n, sizeof(Type), manager_->total());
79  }
80 
81  Type* r = static_cast<Type*>(bypass_malloc(size));
82  while (r == nullptr)
83  {
84  // If malloc fails and there is a std::new_handler, call it to try
85  // free up memory.
86  std::new_handler nh = std::get_new_handler();
87  if (!nh)
88  throw std::bad_alloc();
89  nh();
90  r = static_cast<Type*>(bypass_malloc(size));
91  }
92  return r;
93  }
94 
95  //! Releases a block of storage previously allocated with member allocate
96  //! and not yet released.
97  void deallocate(pointer p, size_type n) const noexcept {
98 
99  manager_->subtract(n * sizeof(Type));
100 
101  if (debug) {
102  printf("deallocate() n=%zu sizeof(T)=%zu total=%zu\n",
103  n, sizeof(Type), manager_->total());
104  }
105 
106  bypass_free(p, n * sizeof(Type));
107  }
108 
109  //! pointer to common Manager object. If we use a reference here, then
110  //! the allocator cannot be default move/assigned anymore.
112 
113  //! Compare to another allocator of same type
114  template <typename Other>
115  bool operator == (const Allocator<Other>& other) const noexcept {
116  return (manager_ == other.manager_);
117  }
118 
119  //! Compare to another allocator of same type
120  template <typename Other>
121  bool operator != (const Allocator<Other>& other) const noexcept {
122  return (manager_ != other.manager_);
123  }
124 };
125 
126 template <>
127 class Allocator<void>
128 {
129 public:
130  using pointer = void*;
131  using const_pointer = const void*;
132  using value_type = void;
133 
134  //! C++11 type flag
135  using is_always_equal = std::false_type;
136 
137  template <typename U>
138  struct rebind { using other = Allocator<U>; };
139 
140  //! Construct Allocator with Manager object
141  explicit Allocator(Manager& manager) noexcept
142  : manager_(&manager) { }
143 
144  //! copy-constructor
145  Allocator(const Allocator&) noexcept = default;
146 
147  //! copy-constructor from a rebound allocator
148  template <typename OtherType>
150  : manager_(other.manager_) { }
151 
152  //! pointer to common Manager object. If we use a reference here, then
153  //! the allocator cannot be default move/assigned anymore.
155 
156  //! Compare to another allocator of same type
157  template <typename Other>
158  bool operator == (const Allocator<Other>& other) const noexcept {
159  return (manager_ == other.manager_);
160  }
161 
162  //! Compare to another allocator of same type
163  template <typename Other>
164  bool operator != (const Allocator<Other>& other) const noexcept {
165  return (manager_ != other.manager_);
166  }
167 };
168 
169 //! operator new with our Allocator
170 template <typename T, typename... Args>
171 T * mm_new(Manager& manager, Args&& ... args) {
172  Allocator<T> allocator(manager);
173  T* value = allocator.allocate(1);
174  allocator.construct(value, std::forward<Args>(args) ...);
175  return value;
176 }
177 
178 //! operator delete with our Allocator
179 template <typename T>
180 void mm_delete(Manager& manager, T* value) {
181  Allocator<T> allocator(manager);
182  allocator.destroy(value);
183  allocator.deallocate(value, 1);
184 }
185 
186 //! std::default_deleter with Manager tracking
187 template <typename T>
188 class Deleter
189 {
190 public:
191  //! constructor: need reference to Manager
192  explicit Deleter(Manager& manager) noexcept
193  : allocator_(manager) { }
194 
195  //! free the pointer
196  void operator () (T* ptr) const noexcept {
197  allocator_.destroy(ptr);
198  allocator_.deallocate(ptr, 1);
199  }
200 
201 private:
202  //! reference to Manager for freeing.
204 };
205 
206 //! unique_ptr with Manager tracking
207 template <typename T>
208 using unique_ptr = std::unique_ptr<T, Deleter<T> >;
209 
210 //! make_unique with Manager tracking
211 template <typename T, typename... Args>
212 unique_ptr<T> make_unique(Manager& manager, Args&& ... args) {
213  return unique_ptr<T>(
214  mm_new<T>(manager, std::forward<Args>(args) ...),
215  Deleter<T>(manager));
216 }
217 
218 //! string with Manager tracking
219 using string = std::basic_string<
220  char, std::char_traits<char>, Allocator<char> >;
221 
222 //! stringbuf with Manager tracking
223 using stringbuf = std::basic_stringbuf<
224  char, std::char_traits<char>, Allocator<char> >;
225 
226 //! vector with Manager tracking
227 template <typename T>
228 using vector = std::vector<T, Allocator<T> >;
229 
230 //! deque with Manager tracking
231 template <typename T>
232 using deque = std::deque<T, Allocator<T> >;
233 
234 } // namespace mem
235 } // namespace thrill
236 
237 #endif // !THRILL_MEM_ALLOCATOR_HEADER
238 
239 /******************************************************************************/
pointer allocate(size_type n, const void *=nullptr)
Definition: allocator.hpp:69
std::false_type is_always_equal
C++11 type flag.
Definition: allocator.hpp:135
bool operator==(const Allocator< Other > &other) const noexcept
Compare to another allocator of same type.
Definition: allocator.hpp:115
std::basic_stringbuf< char, std::char_traits< char >, Allocator< char > > stringbuf
stringbuf with Manager tracking
Definition: allocator.hpp:224
void destroy(pointer p) const noexcept
Destroys in-place the object pointed by p.
bool operator!=(const Allocator< Other > &other) const noexcept
Compare to another allocator of same type.
Definition: allocator.hpp:121
double T
Type
VFS object type.
Definition: file_io.hpp:52
Allocator(const Allocator< OtherType > &other) noexcept
copy-constructor from a rebound allocator
Definition: allocator.hpp:60
Allocator(Manager &manager) noexcept
Construct Allocator with Manager object.
Definition: allocator.hpp:52
std::ptrdiff_t difference_type
Definition: allocator.hpp:42
void deallocate(pointer p, size_type n) const noexcept
Definition: allocator.hpp:97
Deleter(Manager &manager) noexcept
constructor: need reference to Manager
Definition: allocator.hpp:192
Manager & add(size_t amount)
add memory consumption.
Definition: manager.hpp:46
void bypass_free(void *ptr, size_t size) noexcept
bypass malloc tracker and access free() directly
Allocator & operator=(const Allocator &) noexcept=default
copy-assignment operator
void construct(pointer p, const_reference value)
Constructs an element object on the location pointed by p.
Manager & subtract(size_t amount)
subtract memory consumption.
Definition: manager.hpp:55
void * bypass_malloc(size_t size) noexcept
bypass malloc tracker and access malloc() directly
static constexpr bool debug
Definition: allocator.hpp:33
int value
Definition: gen_data.py:41
Allocator(Manager &manager) noexcept
Construct Allocator with Manager object.
Definition: allocator.hpp:141
unique_ptr< T > make_unique(Manager &manager, Args &&... args)
make_unique with Manager tracking
Definition: allocator.hpp:212
Allocator< T > allocator_
reference to Manager for freeing.
Definition: allocator.hpp:203
std::vector< T, Allocator< T > > vector
vector with Manager tracking
Definition: allocator.hpp:228
size_type max_size() const noexcept
Maximum size possible to allocate.
std::deque< T, Allocator< T > > deque
deque with Manager tracking
Definition: allocator.hpp:232
T * mm_new(Manager &manager, Args &&... args)
operator new with our Allocator
Definition: allocator.hpp:171
std::default_deleter with Manager tracking
Definition: allocator.hpp:188
size_t total() const
return total allocation (local value)
Definition: manager.hpp:43
Object shared by allocators and other classes to track memory allocations.
Definition: manager.hpp:28
std::false_type is_always_equal
C++11 type flag.
Definition: allocator.hpp:45
Allocator(const Allocator< OtherType > &other) noexcept
copy-constructor from a rebound allocator
Definition: allocator.hpp:149
std::unique_ptr< T, Deleter< T > > unique_ptr
unique_ptr with Manager tracking
Definition: allocator.hpp:208
void mm_delete(Manager &manager, T *value)
operator delete with our Allocator
Definition: allocator.hpp:180
Return allocator for different type.
Definition: allocator.hpp:49