Fix fibers gdb utils script
[folly.git] / folly / Memory.h
1 /*
2  * Copyright 2016 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::cpp2::FooBarServiceAsyncClient;
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 using SysBufferDeleter = static_function_deleter<void, ::free>;
119 using SysBufferUniquePtr = std::unique_ptr<void, SysBufferDeleter>;
120 inline SysBufferUniquePtr allocate_sys_buffer(size_t size) {
121   return SysBufferUniquePtr(::malloc(size));
122 }
123
124 /**
125  * A SimpleAllocator must provide two methods:
126  *
127  *    void* allocate(size_t size);
128  *    void deallocate(void* ptr);
129  *
130  * which, respectively, allocate a block of size bytes (aligned to the
131  * maximum alignment required on your system), throwing std::bad_alloc
132  * if the allocation can't be satisfied, and free a previously
133  * allocated block.
134  *
135  * SysAlloc resembles the standard allocator.
136  */
137 class SysAlloc {
138  public:
139   void* allocate(size_t size) {
140     void* p = ::malloc(size);
141     if (!p) throw std::bad_alloc();
142     return p;
143   }
144   void deallocate(void* p) {
145     ::free(p);
146   }
147 };
148
149 /**
150  * StlAllocator wraps a SimpleAllocator into a STL-compliant
151  * allocator, maintaining an instance pointer to the simple allocator
152  * object.  The underlying SimpleAllocator object must outlive all
153  * instances of StlAllocator using it.
154  *
155  * But note that if you pass StlAllocator<MallocAllocator,...> to a
156  * standard container it will be larger due to the contained state
157  * pointer.
158  *
159  * @author: Tudor Bosman <tudorb@fb.com>
160  */
161
162 // This would be so much simpler with std::allocator_traits, but gcc 4.6.2
163 // doesn't support it.
164 template <class Alloc, class T> class StlAllocator;
165
166 template <class Alloc> class StlAllocator<Alloc, void> {
167  public:
168   typedef void value_type;
169   typedef void* pointer;
170   typedef const void* const_pointer;
171
172   StlAllocator() : alloc_(nullptr) { }
173   explicit StlAllocator(Alloc* a) : alloc_(a) { }
174
175   Alloc* alloc() const {
176     return alloc_;
177   }
178
179   template <class U> struct rebind {
180     typedef StlAllocator<Alloc, U> other;
181   };
182
183   bool operator!=(const StlAllocator<Alloc, void>& other) const {
184     return alloc_ != other.alloc_;
185   }
186
187   bool operator==(const StlAllocator<Alloc, void>& other) const {
188     return alloc_ == other.alloc_;
189   }
190
191  private:
192   Alloc* alloc_;
193 };
194
195 template <class Alloc, class T>
196 class StlAllocator {
197  public:
198   typedef T value_type;
199   typedef T* pointer;
200   typedef const T* const_pointer;
201   typedef T& reference;
202   typedef const T& const_reference;
203
204   typedef ptrdiff_t difference_type;
205   typedef size_t size_type;
206
207   StlAllocator() : alloc_(nullptr) { }
208   explicit StlAllocator(Alloc* a) : alloc_(a) { }
209
210   template <class U> StlAllocator(const StlAllocator<Alloc, U>& other)
211     : alloc_(other.alloc()) { }
212
213   T* allocate(size_t n, const void* /* hint */ = nullptr) {
214     return static_cast<T*>(alloc_->allocate(n * sizeof(T)));
215   }
216
217   void deallocate(T* p, size_t /* n */) { alloc_->deallocate(p); }
218
219   size_t max_size() const {
220     return std::numeric_limits<size_t>::max();
221   }
222
223   T* address(T& x) const {
224     return std::addressof(x);
225   }
226
227   const T* address(const T& x) const {
228     return std::addressof(x);
229   }
230
231   template <class... Args>
232   void construct(T* p, Args&&... args) {
233     new (p) T(std::forward<Args>(args)...);
234   }
235
236   void destroy(T* p) {
237     p->~T();
238   }
239
240   Alloc* alloc() const {
241     return alloc_;
242   }
243
244   template <class U> struct rebind {
245     typedef StlAllocator<Alloc, U> other;
246   };
247
248   bool operator!=(const StlAllocator<Alloc, T>& other) const {
249     return alloc_ != other.alloc_;
250   }
251
252   bool operator==(const StlAllocator<Alloc, T>& other) const {
253     return alloc_ == other.alloc_;
254   }
255
256  private:
257   Alloc* alloc_;
258 };
259
260 /**
261  * Helper function to obtain rebound allocators
262  *
263  * @author: Marcelo Juchem <marcelo@fb.com>
264  */
265 template <typename T, typename Allocator>
266 typename Allocator::template rebind<T>::other rebind_allocator(
267   Allocator const& allocator
268 ) {
269   return typename Allocator::template rebind<T>::other(allocator);
270 }
271
272 /*
273  * Helper classes/functions for creating a unique_ptr using a custom
274  * allocator.
275  *
276  * @author: Marcelo Juchem <marcelo@fb.com>
277  */
278
279 // Derives from the allocator to take advantage of the empty base
280 // optimization when possible.
281 template <typename Allocator>
282 class allocator_delete
283   : private std::remove_reference<Allocator>::type
284 {
285   typedef typename std::remove_reference<Allocator>::type allocator_type;
286
287 public:
288   typedef typename Allocator::pointer pointer;
289
290   allocator_delete() = default;
291
292   explicit allocator_delete(const allocator_type& allocator)
293     : allocator_type(allocator)
294   {}
295
296   explicit allocator_delete(allocator_type&& allocator)
297     : allocator_type(std::move(allocator))
298   {}
299
300   template <typename U>
301   allocator_delete(const allocator_delete<U>& other)
302     : allocator_type(other.get_allocator())
303   {}
304
305   allocator_type& get_allocator() const {
306     return *const_cast<allocator_delete*>(this);
307   }
308
309   void operator()(pointer p) const {
310     if (!p) return;
311     const_cast<allocator_delete*>(this)->destroy(p);
312     const_cast<allocator_delete*>(this)->deallocate(p, 1);
313   }
314 };
315
316 template <typename T, typename Allocator>
317 class is_simple_allocator {
318   FOLLY_CREATE_HAS_MEMBER_FN_TRAITS(has_destroy, destroy);
319
320   typedef typename std::remove_const<
321     typename std::remove_reference<Allocator>::type
322   >::type allocator;
323   typedef typename std::remove_reference<T>::type value_type;
324   typedef value_type* pointer;
325
326 public:
327   constexpr static bool value = !has_destroy<allocator, void(pointer)>::value
328     && !has_destroy<allocator, void(void*)>::value;
329 };
330
331 template <typename T, typename Allocator>
332 struct as_stl_allocator {
333   typedef typename std::conditional<
334     is_simple_allocator<T, Allocator>::value,
335     folly::StlAllocator<
336       typename std::remove_reference<Allocator>::type,
337       typename std::remove_reference<T>::type
338     >,
339     typename std::remove_reference<Allocator>::type
340   >::type type;
341 };
342
343 template <typename T, typename Allocator>
344 typename std::enable_if<
345   is_simple_allocator<T, Allocator>::value,
346   folly::StlAllocator<
347     typename std::remove_reference<Allocator>::type,
348     typename std::remove_reference<T>::type
349   >
350 >::type make_stl_allocator(Allocator&& allocator) {
351   return folly::StlAllocator<
352     typename std::remove_reference<Allocator>::type,
353     typename std::remove_reference<T>::type
354   >(&allocator);
355 }
356
357 template <typename T, typename Allocator>
358 typename std::enable_if<
359   !is_simple_allocator<T, Allocator>::value,
360   typename std::remove_reference<Allocator>::type
361 >::type make_stl_allocator(Allocator&& allocator) {
362   return std::move(allocator);
363 }
364
365 /**
366  * AllocatorUniquePtr: a unique_ptr that supports both STL-style
367  * allocators and SimpleAllocator
368  *
369  * @author: Marcelo Juchem <marcelo@fb.com>
370  */
371
372 template <typename T, typename Allocator>
373 struct AllocatorUniquePtr {
374   typedef std::unique_ptr<T,
375     folly::allocator_delete<
376       typename std::conditional<
377         is_simple_allocator<T, Allocator>::value,
378         folly::StlAllocator<typename std::remove_reference<Allocator>::type, T>,
379         typename std::remove_reference<Allocator>::type
380       >::type
381     >
382   > type;
383 };
384
385 /**
386  * Functions to allocate a unique_ptr / shared_ptr, supporting both
387  * STL-style allocators and SimpleAllocator, analog to std::allocate_shared
388  *
389  * @author: Marcelo Juchem <marcelo@fb.com>
390  */
391
392 template <typename T, typename Allocator, typename ...Args>
393 typename AllocatorUniquePtr<T, Allocator>::type allocate_unique(
394   Allocator&& allocator, Args&&... args
395 ) {
396   auto stlAllocator = folly::make_stl_allocator<T>(
397     std::forward<Allocator>(allocator)
398   );
399   auto p = stlAllocator.allocate(1);
400
401   try {
402     stlAllocator.construct(p, std::forward<Args>(args)...);
403
404     return {p,
405       folly::allocator_delete<decltype(stlAllocator)>(std::move(stlAllocator))
406     };
407   } catch (...) {
408     stlAllocator.deallocate(p, 1);
409     throw;
410   }
411 }
412
413 template <typename T, typename Allocator, typename ...Args>
414 std::shared_ptr<T> allocate_shared(Allocator&& allocator, Args&&... args) {
415   return std::allocate_shared<T>(
416     folly::make_stl_allocator<T>(std::forward<Allocator>(allocator)),
417     std::forward<Args>(args)...
418   );
419 }
420
421 /**
422  * IsArenaAllocator<T>::value describes whether SimpleAllocator has
423  * no-op deallocate().
424  */
425 template <class T> struct IsArenaAllocator : std::false_type { };
426
427 }  // namespace folly