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