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