folly: add bser encode/decode for dynamic
[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 */) { alloc_->deallocate(p); }
210
211   size_t max_size() const {
212     return std::numeric_limits<size_t>::max();
213   }
214
215   T* address(T& x) const {
216     return std::addressof(x);
217   }
218
219   const T* address(const T& x) const {
220     return std::addressof(x);
221   }
222
223   template <class... Args>
224   void construct(T* p, Args&&... args) {
225     new (p) T(std::forward<Args>(args)...);
226   }
227
228   void destroy(T* p) {
229     p->~T();
230   }
231
232   Alloc* alloc() const {
233     return alloc_;
234   }
235
236   template <class U> struct rebind {
237     typedef StlAllocator<Alloc, U> other;
238   };
239
240   bool operator!=(const StlAllocator<Alloc, T>& other) const {
241     return alloc_ != other.alloc_;
242   }
243
244   bool operator==(const StlAllocator<Alloc, T>& other) const {
245     return alloc_ == other.alloc_;
246   }
247
248  private:
249   Alloc* alloc_;
250 };
251
252 /**
253  * Helper function to obtain rebound allocators
254  *
255  * @author: Marcelo Juchem <marcelo@fb.com>
256  */
257 template <typename T, typename Allocator>
258 typename Allocator::template rebind<T>::other rebind_allocator(
259   Allocator const& allocator
260 ) {
261   return typename Allocator::template rebind<T>::other(allocator);
262 }
263
264 /*
265  * Helper classes/functions for creating a unique_ptr using a custom
266  * allocator.
267  *
268  * @author: Marcelo Juchem <marcelo@fb.com>
269  */
270
271 // Derives from the allocator to take advantage of the empty base
272 // optimization when possible.
273 template <typename Allocator>
274 class allocator_delete
275   : private std::remove_reference<Allocator>::type
276 {
277   typedef typename std::remove_reference<Allocator>::type allocator_type;
278
279 public:
280   typedef typename Allocator::pointer pointer;
281
282   allocator_delete() = default;
283
284   explicit allocator_delete(const allocator_type& allocator)
285     : allocator_type(allocator)
286   {}
287
288   explicit allocator_delete(allocator_type&& allocator)
289     : allocator_type(std::move(allocator))
290   {}
291
292   template <typename U>
293   allocator_delete(const allocator_delete<U>& other)
294     : allocator_type(other.get_allocator())
295   {}
296
297   allocator_type& get_allocator() const {
298     return *const_cast<allocator_delete*>(this);
299   }
300
301   void operator()(pointer p) const {
302     if (!p) return;
303     const_cast<allocator_delete*>(this)->destroy(p);
304     const_cast<allocator_delete*>(this)->deallocate(p, 1);
305   }
306 };
307
308 template <typename T, typename Allocator>
309 class is_simple_allocator {
310   FOLLY_CREATE_HAS_MEMBER_FN_TRAITS(has_destroy, destroy);
311
312   typedef typename std::remove_const<
313     typename std::remove_reference<Allocator>::type
314   >::type allocator;
315   typedef typename std::remove_reference<T>::type value_type;
316   typedef value_type* pointer;
317
318 public:
319   constexpr static bool value = !has_destroy<allocator, void(pointer)>::value
320     && !has_destroy<allocator, void(void*)>::value;
321 };
322
323 template <typename T, typename Allocator>
324 struct as_stl_allocator {
325   typedef typename std::conditional<
326     is_simple_allocator<T, Allocator>::value,
327     folly::StlAllocator<
328       typename std::remove_reference<Allocator>::type,
329       typename std::remove_reference<T>::type
330     >,
331     typename std::remove_reference<Allocator>::type
332   >::type type;
333 };
334
335 template <typename T, typename Allocator>
336 typename std::enable_if<
337   is_simple_allocator<T, Allocator>::value,
338   folly::StlAllocator<
339     typename std::remove_reference<Allocator>::type,
340     typename std::remove_reference<T>::type
341   >
342 >::type make_stl_allocator(Allocator&& allocator) {
343   return folly::StlAllocator<
344     typename std::remove_reference<Allocator>::type,
345     typename std::remove_reference<T>::type
346   >(&allocator);
347 }
348
349 template <typename T, typename Allocator>
350 typename std::enable_if<
351   !is_simple_allocator<T, Allocator>::value,
352   typename std::remove_reference<Allocator>::type
353 >::type make_stl_allocator(Allocator&& allocator) {
354   return std::move(allocator);
355 }
356
357 /**
358  * AllocatorUniquePtr: a unique_ptr that supports both STL-style
359  * allocators and SimpleAllocator
360  *
361  * @author: Marcelo Juchem <marcelo@fb.com>
362  */
363
364 template <typename T, typename Allocator>
365 struct AllocatorUniquePtr {
366   typedef std::unique_ptr<T,
367     folly::allocator_delete<
368       typename std::conditional<
369         is_simple_allocator<T, Allocator>::value,
370         folly::StlAllocator<typename std::remove_reference<Allocator>::type, T>,
371         typename std::remove_reference<Allocator>::type
372       >::type
373     >
374   > type;
375 };
376
377 /**
378  * Functions to allocate a unique_ptr / shared_ptr, supporting both
379  * STL-style allocators and SimpleAllocator, analog to std::allocate_shared
380  *
381  * @author: Marcelo Juchem <marcelo@fb.com>
382  */
383
384 template <typename T, typename Allocator, typename ...Args>
385 typename AllocatorUniquePtr<T, Allocator>::type allocate_unique(
386   Allocator&& allocator, Args&&... args
387 ) {
388   auto stlAllocator = folly::make_stl_allocator<T>(
389     std::forward<Allocator>(allocator)
390   );
391   auto p = stlAllocator.allocate(1);
392
393   try {
394     stlAllocator.construct(p, std::forward<Args>(args)...);
395
396     return {p,
397       folly::allocator_delete<decltype(stlAllocator)>(std::move(stlAllocator))
398     };
399   } catch (...) {
400     stlAllocator.deallocate(p, 1);
401     throw;
402   }
403 }
404
405 template <typename T, typename Allocator, typename ...Args>
406 std::shared_ptr<T> allocate_shared(Allocator&& allocator, Args&&... args) {
407   return std::allocate_shared<T>(
408     folly::make_stl_allocator<T>(std::forward<Allocator>(allocator)),
409     std::forward<Args>(args)...
410   );
411 }
412
413 /**
414  * IsArenaAllocator<T>::value describes whether SimpleAllocator has
415  * no-op deallocate().
416  */
417 template <class T> struct IsArenaAllocator : std::false_type { };
418
419 }  // namespace folly
420
421 #endif /* FOLLY_MEMORY_H_ */