thrust
allocate_unique.h
1 // Copyright (c) 2018 NVIDIA Corporation
2 // Author: Bryce Adelstein Lelbach <brycelelbach@gmail.com>
3 //
4 // Distributed under the Boost Software License v1.0 (boost.org/LICENSE_1_0.txt)
5 
6 #pragma once
7 
8 #include <thrust/detail/config.h>
9 #include <thrust/detail/cpp11_required.h>
10 
11 #if THRUST_CPP_DIALECT >= 2011
12 
13 #include <thrust/detail/raw_pointer_cast.h>
14 #include <thrust/detail/type_deduction.h>
15 #include <thrust/detail/memory_algorithms.h>
16 #include <thrust/detail/allocator/allocator_traits.h>
17 
18 #include <utility>
19 #include <memory>
20 
21 THRUST_BEGIN_NS
22 
23 // wg21.link/p0316r0
24 
26 
27 namespace detail
28 {
29 
30 template <typename Allocator, typename Pointer>
31 void allocator_delete_impl(
32  Allocator const& alloc, Pointer p, std::false_type
33 )
34 {
35  using traits = typename detail::allocator_traits<
36  typename std::remove_cv<
37  typename std::remove_reference<Allocator>::type
38  >::type
39  >;
40 
41  typename traits::allocator_type alloc_T(alloc);
42 
43  if (nullptr != pointer_traits<Pointer>::get(p))
44  {
45  traits::destroy(alloc_T, thrust::raw_pointer_cast(p));
46  traits::deallocate(alloc_T, p, 1);
47  }
48 }
49 
50 template <typename Allocator, typename Pointer>
51 void allocator_delete_impl(
52  Allocator const& alloc, Pointer p, std::true_type
53 )
54 {
55  using traits = typename detail::allocator_traits<
56  typename std::remove_cv<
57  typename std::remove_reference<Allocator>::type
58  >::type
59  >;
60 
61  typename traits::allocator_type alloc_T(alloc);
62 
63  if (nullptr != pointer_traits<Pointer>::get(p))
64  {
65  traits::deallocate(alloc_T, p, 1);
66  }
67 }
68 
69 } // namespace detail
70 
71 template <typename T, typename Allocator, bool Uninitialized = false>
72 struct allocator_delete final
73 {
74  using allocator_type
75  = typename std::remove_cv<
76  typename std::remove_reference<Allocator>::type
77  >::type::template rebind<T>::other;
78  using pointer = typename detail::allocator_traits<allocator_type>::pointer;
79 
80  template <typename UAllocator>
81  allocator_delete(UAllocator&& other) noexcept
82  : alloc_(THRUST_FWD(other))
83  {}
84 
85  template <typename U, typename UAllocator>
86  allocator_delete(
87  allocator_delete<U, UAllocator> const& other
88  ) noexcept
89  : alloc_(other.get_allocator())
90  {}
91  template <typename U, typename UAllocator>
92  allocator_delete(
93  allocator_delete<U, UAllocator>&& other
94  ) noexcept
95  : alloc_(std::move(other.get_allocator()))
96  {}
97 
98  template <typename U, typename UAllocator>
99  allocator_delete& operator=(
100  allocator_delete<U, UAllocator> const& other
101  ) noexcept
102  {
103  alloc_ = other.get_allocator();
104  return *this;
105  }
106  template <typename U, typename UAllocator>
107  allocator_delete& operator=(
108  allocator_delete<U, UAllocator>&& other
109  ) noexcept
110  {
111  alloc_ = std::move(other.get_allocator());
112  return *this;
113  }
114 
115  void operator()(pointer p)
116  {
117  std::integral_constant<bool, Uninitialized> ic;
118 
119  detail::allocator_delete_impl(get_allocator(), p, ic);
120  }
121 
122  allocator_type& get_allocator() noexcept { return alloc_; }
123  allocator_type const& get_allocator() const noexcept { return alloc_; }
124 
125  void swap(allocator_delete& other) noexcept
126  {
127  using std::swap;
128  swap(alloc_, other.alloc_);
129  }
130 
131 private:
132  allocator_type alloc_;
133 };
134 
135 template <typename T, typename Allocator>
136 using uninitialized_allocator_delete = allocator_delete<T, Allocator, true>;
137 
138 namespace detail {
139 
140 template <typename Allocator, typename Pointer, typename Size>
141 void array_allocator_delete_impl(
142  Allocator const& alloc, Pointer p, Size count, std::false_type
143 )
144 {
145  using traits = typename detail::allocator_traits<
146  typename std::remove_cv<
147  typename std::remove_reference<Allocator>::type
148  >::type
149  >;
150 
151  typename traits::allocator_type alloc_T(alloc);
152 
153  if (nullptr != pointer_traits<Pointer>::get(p))
154  {
155  destroy_n(alloc_T, p, count);
156  traits::deallocate(alloc_T, p, count);
157  }
158 }
159 
160 template <typename Allocator, typename Pointer, typename Size>
161 void array_allocator_delete_impl(
162  Allocator const& alloc, Pointer p, Size count, std::true_type
163 )
164 {
165  using traits = typename detail::allocator_traits<
166  typename std::remove_cv<
167  typename std::remove_reference<Allocator>::type
168  >::type
169  >;
170 
171  typename traits::allocator_type alloc_T(alloc);
172 
173  if (nullptr != pointer_traits<Pointer>::get(p))
174  {
175  traits::deallocate(alloc_T, p, count);
176  }
177 }
178 
179 } // namespace detail
180 
181 template <typename T, typename Allocator, bool Uninitialized = false>
182 struct array_allocator_delete final
183 {
184  using allocator_type
185  = typename std::remove_cv<
186  typename std::remove_reference<Allocator>::type
187  >::type::template rebind<T>::other;
188  using pointer = typename detail::allocator_traits<allocator_type>::pointer;
189 
190  template <typename UAllocator>
191  array_allocator_delete(UAllocator&& other, std::size_t n) noexcept
192  : alloc_(THRUST_FWD(other)), count_(n)
193  {}
194 
195  template <typename U, typename UAllocator>
196  array_allocator_delete(
197  array_allocator_delete<U, UAllocator> const& other
198  ) noexcept
199  : alloc_(other.get_allocator()), count_(other.count_)
200  {}
201  template <typename U, typename UAllocator>
202  array_allocator_delete(
203  array_allocator_delete<U, UAllocator>&& other
204  ) noexcept
205  : alloc_(std::move(other.get_allocator())), count_(other.count_)
206  {}
207 
208  template <typename U, typename UAllocator>
209  array_allocator_delete& operator=(
210  array_allocator_delete<U, UAllocator> const& other
211  ) noexcept
212  {
213  alloc_ = other.get_allocator();
214  count_ = other.count_;
215  return *this;
216  }
217  template <typename U, typename UAllocator>
218  array_allocator_delete& operator=(
219  array_allocator_delete<U, UAllocator>&& other
220  ) noexcept
221  {
222  alloc_ = std::move(other.get_allocator());
223  count_ = other.count_;
224  return *this;
225  }
226 
227  void operator()(pointer p)
228  {
229  std::integral_constant<bool, Uninitialized> ic;
230 
231  detail::array_allocator_delete_impl(get_allocator(), p, count_, ic);
232  }
233 
234  allocator_type& get_allocator() noexcept { return alloc_; }
235  allocator_type const& get_allocator() const noexcept { return alloc_; }
236 
237  void swap(array_allocator_delete& other) noexcept
238  {
239  using std::swap;
240  swap(alloc_, other.alloc_);
241  swap(count_, other.count_);
242  }
243 
244 private:
245  allocator_type alloc_;
246  std::size_t count_;
247 };
248 
249 template <typename T, typename Allocator>
250 using uninitialized_array_allocator_delete
251  = array_allocator_delete<T, Allocator, true>;
252 
254 
255 template <typename Pointer, typename Lambda>
256 struct tagged_deleter : Lambda
257 {
258  __host__ __device__
259  tagged_deleter(Lambda&& l) : Lambda(THRUST_FWD(l)) {}
260 
261  using pointer = Pointer;
262 };
263 
264 template <typename Pointer, typename Lambda>
265 __host__ __device__
266 tagged_deleter<Pointer, Lambda>
267 make_tagged_deleter(Lambda&& l)
268 {
269  return tagged_deleter<Pointer, Lambda>(THRUST_FWD(l));
270 }
271 
273 
274 template <typename T, typename Allocator, typename... Args>
275 __host__
276 std::unique_ptr<
277  T,
278  allocator_delete<
279  T
280  , typename detail::allocator_traits<
281  typename std::remove_cv<
282  typename std::remove_reference<Allocator>::type
283  >::type
284  >::template rebind_traits<T>::allocator_type
285  >
286 >
287 allocate_unique(
288  Allocator const& alloc, Args&&... args
289 )
290 {
291  using traits = typename detail::allocator_traits<
292  typename std::remove_cv<
293  typename std::remove_reference<Allocator>::type
294  >::type
295  >::template rebind_traits<T>;
296 
297  typename traits::allocator_type alloc_T(alloc);
298 
299  auto hold_deleter = make_tagged_deleter<typename traits::pointer>(
300  [&alloc_T] (typename traits::pointer p) {
301  traits::deallocate(alloc_T, p, 1);
302  }
303  );
304  using hold_t = std::unique_ptr<T, decltype(hold_deleter)>;
305  auto hold = hold_t(traits::allocate(alloc_T, 1), hold_deleter);
306 
307  traits::construct(
308  alloc_T, thrust::raw_pointer_cast(hold.get()), THRUST_FWD(args)...
309  );
310  auto deleter = allocator_delete<T, typename traits::allocator_type>(alloc);
311  return std::unique_ptr<T, decltype(deleter)>
312  (hold.release(), std::move(deleter));
313 }
314 
315 template <typename T, typename Allocator>
316 __host__
317 std::unique_ptr<
318  T,
319  uninitialized_allocator_delete<
320  T
321  , typename detail::allocator_traits<
322  typename std::remove_cv<
323  typename std::remove_reference<Allocator>::type
324  >::type
325  >::template rebind_traits<T>::allocator_type
326  >
327 >
328 uninitialized_allocate_unique(
329  Allocator const& alloc
330 )
331 {
332  using traits = typename detail::allocator_traits<
333  typename std::remove_cv<
334  typename std::remove_reference<Allocator>::type
335  >::type
336  >::template rebind_traits<T>;
337 
338  typename traits::allocator_type alloc_T(alloc);
339 
340  auto hold_deleter = make_tagged_deleter<typename traits::pointer>(
341  [&alloc_T] (typename traits::pointer p) {
342  traits::deallocate(alloc_T, p, 1);
343  }
344  );
345  using hold_t = std::unique_ptr<T, decltype(hold_deleter)>;
346  auto hold = hold_t(traits::allocate(alloc_T, 1), hold_deleter);
347 
348  auto deleter = uninitialized_allocator_delete<
349  T, typename traits::allocator_type
350  >(alloc_T);
351  return std::unique_ptr<T, decltype(deleter)>
352  (hold.release(), std::move(deleter));
353 }
354 
355 template <typename T, typename Allocator, typename Size, typename... Args>
356 __host__
357 std::unique_ptr<
358  T[],
359  array_allocator_delete<
360  T
361  , typename detail::allocator_traits<
362  typename std::remove_cv<
363  typename std::remove_reference<Allocator>::type
364  >::type
365  >::template rebind_traits<T>::allocator_type
366  >
367 >
368 allocate_unique_n(
369  Allocator const& alloc, Size n, Args&&... args
370 )
371 {
372  using traits = typename detail::allocator_traits<
373  typename std::remove_cv<
374  typename std::remove_reference<Allocator>::type
375  >::type
376  >::template rebind_traits<T>;
377 
378  typename traits::allocator_type alloc_T(alloc);
379 
380  auto hold_deleter = make_tagged_deleter<typename traits::pointer>(
381  [n, &alloc_T] (typename traits::pointer p) {
382  traits::deallocate(alloc_T, p, n);
383  }
384  );
385  using hold_t = std::unique_ptr<T[], decltype(hold_deleter)>;
386  auto hold = hold_t(traits::allocate(alloc_T, n), hold_deleter);
387 
388  uninitialized_construct_n_with_allocator(
389  alloc_T, hold.get(), n, THRUST_FWD(args)...
390  );
391  auto deleter = array_allocator_delete<
392  T, typename traits::allocator_type
393  >(alloc_T, n);
394  return std::unique_ptr<T[], decltype(deleter)>
395  (hold.release(), std::move(deleter));
396 }
397 
398 template <typename T, typename Allocator, typename Size>
399 __host__
400 std::unique_ptr<
401  T[],
402  uninitialized_array_allocator_delete<
403  T
404  , typename detail::allocator_traits<
405  typename std::remove_cv<
406  typename std::remove_reference<Allocator>::type
407  >::type
408  >::template rebind_traits<T>::allocator_type
409  >
410 >
411 uninitialized_allocate_unique_n(
412  Allocator const& alloc, Size n
413 )
414 {
415  using traits = typename detail::allocator_traits<
416  typename std::remove_cv<
417  typename std::remove_reference<Allocator>::type
418  >::type
419  >::template rebind_traits<T>;
420 
421  typename traits::allocator_type alloc_T(alloc);
422 
423  auto hold_deleter = make_tagged_deleter<typename traits::pointer>(
424  [n, &alloc_T] (typename traits::pointer p) {
425  traits::deallocate(alloc_T, p, n);
426  }
427  );
428  using hold_t = std::unique_ptr<T[], decltype(hold_deleter)>;
429  auto hold = hold_t(traits::allocate(alloc_T, n), hold_deleter);
430 
431  auto deleter = uninitialized_array_allocator_delete<
432  T, typename traits::allocator_type
433  >(alloc_T, n);
434  return std::unique_ptr<T[], decltype(deleter)>
435  (hold.release(), std::move(deleter));
436 }
437 
439 
440 THRUST_END_NS
441 
442 #endif // THRUST_CPP_DIALECT >= 2011
443 
__host__ __device__ access_traits< typename tuple_element< N, detail::cons< HT, TT > >::type >::non_const_type get(detail::cons< HT, TT > &t)
__host__ __device__ thrust::iterator_traits< InputIterator >::difference_type count(const thrust::detail::execution_policy_base< DerivedPolicy > &exec, InputIterator first, InputIterator last, const EqualityComparable &value)
__host__ __device__ thrust::detail::pointer_traits< Pointer >::raw_pointer raw_pointer_cast(Pointer ptr)
__host__ __device__ void swap(device_reference< T > x, device_reference< T > y)