Support unique_ptr instances with custom deleters in to_shared_ptr
[folly.git] / folly / Memory.h
1 /*
2  * Copyright 2015 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #ifndef FOLLY_MEMORY_H_
18 #define FOLLY_MEMORY_H_
19
20 #include <folly/Traits.h>
21
22 #include <cstddef>
23 #include <cstdlib>
24 #include <exception>
25 #include <limits>
26 #include <memory>
27 #include <stdexcept>
28 #include <utility>
29
30 namespace folly {
31
32 /**
33  * For exception safety and consistency with make_shared. Erase me when
34  * we have std::make_unique().
35  *
36  * @author Louis Brandy (ldbrandy@fb.com)
37  * @author Xu Ning (xning@fb.com)
38  */
39
40 template<typename T, typename Dp = std::default_delete<T>, typename... Args>
41 typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T, Dp>>::type
42 make_unique(Args&&... args) {
43   return std::unique_ptr<T, Dp>(new T(std::forward<Args>(args)...));
44 }
45
46 // Allows 'make_unique<T[]>(10)'. (N3690 s20.9.1.4 p3-4)
47 template<typename T, typename Dp = std::default_delete<T>>
48 typename std::enable_if<std::is_array<T>::value, std::unique_ptr<T, Dp>>::type
49 make_unique(const size_t n) {
50   return std::unique_ptr<T, Dp>(new typename std::remove_extent<T>::type[n]());
51 }
52
53 // Disallows 'make_unique<T[10]>()'. (N3690 s20.9.1.4 p5)
54 template<typename T, typename Dp = std::default_delete<T>, typename... Args>
55 typename std::enable_if<
56   std::extent<T>::value != 0, std::unique_ptr<T, Dp>>::type
57 make_unique(Args&&...) = delete;
58
59 /**
60  * static_function_deleter
61  *
62  * So you can write this:
63  *
64  *      using RSA_deleter = folly::static_function_deleter<RSA, &RSA_free>;
65  *      auto rsa = std::unique_ptr<RSA, RSA_deleter>(RSA_new());
66  *      RSA_generate_key_ex(rsa.get(), bits, exponent, nullptr);
67  *      rsa = nullptr;  // calls RSA_free(rsa.get())
68  *
69  * This would be sweet as well for BIO, but unfortunately BIO_free has signature
70  * int(BIO*) while we require signature void(BIO*). So you would need to make a
71  * wrapper for it:
72  *
73  *      inline void BIO_free_fb(BIO* bio) { CHECK_EQ(1, BIO_free(bio)); }
74  *      using BIO_deleter = folly::static_function_deleter<BIO, &BIO_free_fb>;
75  *      auto buf = std::unique_ptr<BIO, BIO_deleter>(BIO_new(BIO_s_mem()));
76  *      buf = nullptr;  // calls BIO_free(buf.get())
77  */
78
79 template <typename T, void(*f)(T*)>
80 struct static_function_deleter {
81   void operator()(T* t) { f(t); }
82 };
83
84 /**
85  *  to_shared_ptr
86  *
87  *  Convert unique_ptr to shared_ptr without specifying the template type
88  *  parameter and letting the compiler deduce it.
89  *
90  *  So you can write this:
91  *
92  *      auto sptr = to_shared_ptr(getSomethingUnique<T>());
93  *
94  *  Instead of this:
95  *
96  *      auto sptr = shared_ptr<T>(getSomethingUnique<T>());
97  *
98  *  Useful when `T` is long, such as:
99  *
100  *      using T = foobar::cpp2::FooBarServiceAsyncClient;
101  */
102 template <typename T, typename D>
103 std::shared_ptr<T> to_shared_ptr(std::unique_ptr<T, D>&& ptr) {
104   return std::shared_ptr<T>(std::move(ptr));
105 }
106
107 /**
108  * A SimpleAllocator must provide two methods:
109  *
110  *    void* allocate(size_t size);
111  *    void deallocate(void* ptr);
112  *
113  * which, respectively, allocate a block of size bytes (aligned to the
114  * maximum alignment required on your system), throwing std::bad_alloc
115  * if the allocation can't be satisfied, and free a previously
116  * allocated block.
117  *
118  * SysAlloc resembles the standard allocator.
119  */
120 class SysAlloc {
121  public:
122   void* allocate(size_t size) {
123     void* p = ::malloc(size);
124     if (!p) throw std::bad_alloc();
125     return p;
126   }
127   void deallocate(void* p) {
128     ::free(p);
129   }
130 };
131
132 /**
133  * StlAllocator wraps a SimpleAllocator into a STL-compliant
134  * allocator, maintaining an instance pointer to the simple allocator
135  * object.  The underlying SimpleAllocator object must outlive all
136  * instances of StlAllocator using it.
137  *
138  * But note that if you pass StlAllocator<MallocAllocator,...> to a
139  * standard container it will be larger due to the contained state
140  * pointer.
141  *
142  * @author: Tudor Bosman <tudorb@fb.com>
143  */
144
145 // This would be so much simpler with std::allocator_traits, but gcc 4.6.2
146 // doesn't support it.
147 template <class Alloc, class T> class StlAllocator;
148
149 template <class Alloc> class StlAllocator<Alloc, void> {
150  public:
151   typedef void value_type;
152   typedef void* pointer;
153   typedef const void* const_pointer;
154
155   StlAllocator() : alloc_(nullptr) { }
156   explicit StlAllocator(Alloc* a) : alloc_(a) { }
157
158   Alloc* alloc() const {
159     return alloc_;
160   }
161
162   template <class U> struct rebind {
163     typedef StlAllocator<Alloc, U> other;
164   };
165
166   bool operator!=(const StlAllocator<Alloc, void>& other) const {
167     return alloc_ != other.alloc_;
168   }
169
170   bool operator==(const StlAllocator<Alloc, void>& other) const {
171     return alloc_ == other.alloc_;
172   }
173
174  private:
175   Alloc* alloc_;
176 };
177
178 template <class Alloc, class T>
179 class StlAllocator {
180  public:
181   typedef T value_type;
182   typedef T* pointer;
183   typedef const T* const_pointer;
184   typedef T& reference;
185   typedef const T& const_reference;
186
187   typedef ptrdiff_t difference_type;
188   typedef size_t size_type;
189
190   StlAllocator() : alloc_(nullptr) { }
191   explicit StlAllocator(Alloc* a) : alloc_(a) { }
192
193   template <class U> StlAllocator(const StlAllocator<Alloc, U>& other)
194     : alloc_(other.alloc()) { }
195
196   T* allocate(size_t n, const void* hint = nullptr) {
197     return static_cast<T*>(alloc_->allocate(n * sizeof(T)));
198   }
199
200   void deallocate(T* p, size_t n) {
201     alloc_->deallocate(p);
202   }
203
204   size_t max_size() const {
205     return std::numeric_limits<size_t>::max();
206   }
207
208   T* address(T& x) const {
209     return std::addressof(x);
210   }
211
212   const T* address(const T& x) const {
213     return std::addressof(x);
214   }
215
216   template <class... Args>
217   void construct(T* p, Args&&... args) {
218     new (p) T(std::forward<Args>(args)...);
219   }
220
221   void destroy(T* p) {
222     p->~T();
223   }
224
225   Alloc* alloc() const {
226     return alloc_;
227   }
228
229   template <class U> struct rebind {
230     typedef StlAllocator<Alloc, U> other;
231   };
232
233   bool operator!=(const StlAllocator<Alloc, T>& other) const {
234     return alloc_ != other.alloc_;
235   }
236
237   bool operator==(const StlAllocator<Alloc, T>& other) const {
238     return alloc_ == other.alloc_;
239   }
240
241  private:
242   Alloc* alloc_;
243 };
244
245 /**
246  * Helper function to obtain rebound allocators
247  *
248  * @author: Marcelo Juchem <marcelo@fb.com>
249  */
250 template <typename T, typename Allocator>
251 typename Allocator::template rebind<T>::other rebind_allocator(
252   Allocator const& allocator
253 ) {
254   return typename Allocator::template rebind<T>::other(allocator);
255 }
256
257 /*
258  * Helper classes/functions for creating a unique_ptr using a custom
259  * allocator.
260  *
261  * @author: Marcelo Juchem <marcelo@fb.com>
262  */
263
264 // Derives from the allocator to take advantage of the empty base
265 // optimization when possible.
266 template <typename Allocator>
267 class allocator_delete
268   : private std::remove_reference<Allocator>::type
269 {
270   typedef typename std::remove_reference<Allocator>::type allocator_type;
271
272 public:
273   typedef typename Allocator::pointer pointer;
274
275   allocator_delete() = default;
276
277   explicit allocator_delete(const allocator_type& allocator)
278     : allocator_type(allocator)
279   {}
280
281   explicit allocator_delete(allocator_type&& allocator)
282     : allocator_type(std::move(allocator))
283   {}
284
285   template <typename U>
286   allocator_delete(const allocator_delete<U>& other)
287     : allocator_type(other.get_allocator())
288   {}
289
290   allocator_type& get_allocator() const {
291     return *const_cast<allocator_delete*>(this);
292   }
293
294   void operator()(pointer p) const {
295     if (!p) return;
296     const_cast<allocator_delete*>(this)->destroy(p);
297     const_cast<allocator_delete*>(this)->deallocate(p, 1);
298   }
299 };
300
301 template <typename T, typename Allocator>
302 class is_simple_allocator {
303   FOLLY_CREATE_HAS_MEMBER_FN_TRAITS(has_destroy, destroy);
304
305   typedef typename std::remove_const<
306     typename std::remove_reference<Allocator>::type
307   >::type allocator;
308   typedef typename std::remove_reference<T>::type value_type;
309   typedef value_type* pointer;
310
311 public:
312   constexpr static bool value = !has_destroy<allocator, void(pointer)>::value
313     && !has_destroy<allocator, void(void*)>::value;
314 };
315
316 template <typename T, typename Allocator>
317 struct as_stl_allocator {
318   typedef typename std::conditional<
319     is_simple_allocator<T, Allocator>::value,
320     folly::StlAllocator<
321       typename std::remove_reference<Allocator>::type,
322       typename std::remove_reference<T>::type
323     >,
324     typename std::remove_reference<Allocator>::type
325   >::type type;
326 };
327
328 template <typename T, typename Allocator>
329 typename std::enable_if<
330   is_simple_allocator<T, Allocator>::value,
331   folly::StlAllocator<
332     typename std::remove_reference<Allocator>::type,
333     typename std::remove_reference<T>::type
334   >
335 >::type make_stl_allocator(Allocator&& allocator) {
336   return folly::StlAllocator<
337     typename std::remove_reference<Allocator>::type,
338     typename std::remove_reference<T>::type
339   >(&allocator);
340 }
341
342 template <typename T, typename Allocator>
343 typename std::enable_if<
344   !is_simple_allocator<T, Allocator>::value,
345   typename std::remove_reference<Allocator>::type
346 >::type make_stl_allocator(Allocator&& allocator) {
347   return std::move(allocator);
348 }
349
350 /**
351  * AllocatorUniquePtr: a unique_ptr that supports both STL-style
352  * allocators and SimpleAllocator
353  *
354  * @author: Marcelo Juchem <marcelo@fb.com>
355  */
356
357 template <typename T, typename Allocator>
358 struct AllocatorUniquePtr {
359   typedef std::unique_ptr<T,
360     folly::allocator_delete<
361       typename std::conditional<
362         is_simple_allocator<T, Allocator>::value,
363         folly::StlAllocator<typename std::remove_reference<Allocator>::type, T>,
364         typename std::remove_reference<Allocator>::type
365       >::type
366     >
367   > type;
368 };
369
370 /**
371  * Functions to allocate a unique_ptr / shared_ptr, supporting both
372  * STL-style allocators and SimpleAllocator, analog to std::allocate_shared
373  *
374  * @author: Marcelo Juchem <marcelo@fb.com>
375  */
376
377 template <typename T, typename Allocator, typename ...Args>
378 typename AllocatorUniquePtr<T, Allocator>::type allocate_unique(
379   Allocator&& allocator, Args&&... args
380 ) {
381   auto stlAllocator = folly::make_stl_allocator<T>(
382     std::forward<Allocator>(allocator)
383   );
384   auto p = stlAllocator.allocate(1);
385
386   try {
387     stlAllocator.construct(p, std::forward<Args>(args)...);
388
389     return {p,
390       folly::allocator_delete<decltype(stlAllocator)>(std::move(stlAllocator))
391     };
392   } catch (...) {
393     stlAllocator.deallocate(p, 1);
394     throw;
395   }
396 }
397
398 template <typename T, typename Allocator, typename ...Args>
399 std::shared_ptr<T> allocate_shared(Allocator&& allocator, Args&&... args) {
400   return std::allocate_shared<T>(
401     folly::make_stl_allocator<T>(std::forward<Allocator>(allocator)),
402     std::forward<Args>(args)...
403   );
404 }
405
406 /**
407  * IsArenaAllocator<T>::value describes whether SimpleAllocator has
408  * no-op deallocate().
409  */
410 template <class T> struct IsArenaAllocator : std::false_type { };
411
412 }  // namespace folly
413
414 #endif /* FOLLY_MEMORY_H_ */