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