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