2 * Copyright 2013 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #ifndef FOLLY_STLALLOCATOR_H_
18 #define FOLLY_STLALLOCATOR_H_
20 #include "folly/Traits.h"
33 * Wrap a SimpleAllocator into a STL-compliant allocator.
35 * The SimpleAllocator must provide two methods:
36 * void* allocate(size_t size);
37 * void deallocate(void* ptr, size_t size);
38 * which, respectively, allocate a block of size bytes (aligned to the maximum
39 * alignment required on your system), throwing std::bad_alloc if the
40 * allocation can't be satisfied, and free a previously allocated block.
42 * Note that the following allocator resembles the standard allocator
45 * class MallocAllocator {
47 * void* allocate(size_t size) {
48 * void* p = malloc(size);
49 * if (!p) throw std::bad_alloc();
52 * void deallocate(void* p) {
57 * author: Tudor Bosman <tudorb@fb.com>
60 // This would be so much simpler with std::allocator_traits, but gcc 4.6.2
62 template <class Alloc, class T> class StlAllocator;
64 template <class Alloc> class StlAllocator<Alloc, void> {
66 typedef void value_type;
67 typedef void* pointer;
68 typedef const void* const_pointer;
69 template <class U> struct rebind {
70 typedef StlAllocator<Alloc, U> other;
74 template <class Alloc, class T>
79 typedef const T* const_pointer;
81 typedef const T& const_reference;
83 typedef ptrdiff_t difference_type;
84 typedef size_t size_type;
86 StlAllocator() : alloc_(nullptr) { }
87 explicit StlAllocator(Alloc* alloc) : alloc_(alloc) { }
89 template <class U> StlAllocator(const StlAllocator<Alloc, U>& other)
90 : alloc_(other.alloc()) { }
92 T* allocate(size_t n, const void* hint = nullptr) {
93 return static_cast<T*>(alloc_->allocate(n * sizeof(T)));
96 void deallocate(T* p, size_t n) {
97 alloc_->deallocate(p);
100 size_t max_size() const {
101 return std::numeric_limits<size_t>::max();
104 T* address(T& x) const {
105 return std::addressof(x);
108 const T* address(const T& x) const {
109 return std::addressof(x);
112 template <class... Args>
113 void construct(T* p, Args&&... args) {
114 new (p) T(std::forward<Args>(args)...);
121 Alloc* alloc() const {
125 template <class U> struct rebind {
126 typedef StlAllocator<Alloc, U> other;
129 bool operator!=(const StlAllocator<Alloc, T>& other) const {
130 return alloc_ != other.alloc_;
133 bool operator==(const StlAllocator<Alloc, T>& other) const {
134 return alloc_ == other.alloc_;
142 * Helper classes/functions for creating a unique_ptr using a custom allocator
144 * @author: Marcelo Juchem <marcelo@fb.com>
147 // A deleter implementation based on std::default_delete,
148 // which uses a custom allocator to free memory
149 template <typename Allocator>
150 class allocator_delete {
151 typedef typename std::remove_reference<Allocator>::type allocator_type;
154 allocator_delete() = default;
156 explicit allocator_delete(const allocator_type& allocator):
157 allocator_(allocator)
160 explicit allocator_delete(allocator_type&& allocator):
161 allocator_(std::move(allocator))
164 template <typename U>
165 allocator_delete(const allocator_delete<U>& other):
166 allocator_(other.get_allocator())
169 allocator_type& get_allocator() const {
173 void operator()(typename allocator_type::pointer p) const {
178 allocator_.destroy(p);
179 allocator_.deallocate(p, 1);
183 mutable allocator_type allocator_;
186 template <typename T, typename Allocator>
187 class is_simple_allocator {
188 FOLLY_CREATE_HAS_MEMBER_FN_TRAITS(has_destroy, destroy);
190 typedef typename std::remove_const<
191 typename std::remove_reference<Allocator>::type
193 typedef typename std::remove_reference<T>::type value_type;
194 typedef value_type* pointer;
197 constexpr static bool value = !has_destroy<allocator, void(pointer)>::value
198 && !has_destroy<allocator, void(void*)>::value;
201 template <typename T, typename Allocator>
202 typename std::enable_if<
203 is_simple_allocator<T, Allocator>::value,
205 typename std::remove_reference<Allocator>::type,
206 typename std::remove_reference<T>::type
208 >::type make_stl_allocator(Allocator&& allocator) {
209 return folly::StlAllocator<
210 typename std::remove_reference<Allocator>::type,
211 typename std::remove_reference<T>::type
215 template <typename T, typename Allocator>
216 typename std::enable_if<
217 !is_simple_allocator<T, Allocator>::value,
218 typename std::remove_reference<Allocator>::type
219 >::type make_stl_allocator(Allocator&& allocator) {
220 return std::move(allocator);
223 template <typename T, typename Allocator>
224 struct AllocatorUniquePtr {
225 typedef std::unique_ptr<T,
226 folly::allocator_delete<
227 typename std::conditional<
228 is_simple_allocator<T, Allocator>::value,
229 folly::StlAllocator<typename std::remove_reference<Allocator>::type, T>,
230 typename std::remove_reference<Allocator>::type
236 template <typename T, typename Allocator, typename ...Args>
237 typename AllocatorUniquePtr<T, Allocator>::type allocate_unique(
238 Allocator&& allocator, Args&&... args
240 auto stlAllocator = folly::make_stl_allocator<T>(
241 std::forward<Allocator>(allocator)
243 auto p = stlAllocator.allocate(1);
246 stlAllocator.construct(p, std::forward<Args>(args)...);
249 folly::allocator_delete<decltype(stlAllocator)>(std::move(stlAllocator))
252 stlAllocator.deallocate(p, 1);
257 template <typename T, typename Allocator, typename ...Args>
258 std::shared_ptr<T> allocate_shared(Allocator&& allocator, Args&&... args) {
259 return std::allocate_shared<T>(
260 folly::make_stl_allocator<T>(std::forward<Allocator>(allocator)),
261 std::forward<Args>(args)...
267 #endif /* FOLLY_STLALLOCATOR_H_ */