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