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