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