1 /*
2  * Copyright (C) 2016 The Android Open Source Project
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 LIBMEMUNREACHABLE_ALLOCATOR_H_
18 #define LIBMEMUNREACHABLE_ALLOCATOR_H_
19 
20 #include <atomic>
21 #include <cstddef>
22 #include <functional>
23 #include <list>
24 #include <map>
25 #include <memory>
26 #include <set>
27 #include <unordered_map>
28 #include <unordered_set>
29 #include <vector>
30 extern std::atomic<int> heap_count;
31 
32 class HeapImpl;
33 
34 template<typename T>
35 class Allocator;
36 
37 
38 // Non-templated class that implements wraps HeapImpl to keep
39 // implementation out of the header file
40 class Heap {
41 public:
42   Heap();
43   ~Heap();
44 
45   // Copy constructor that does not take ownership of impl_
Heap(const Heap & other)46   Heap(const Heap& other) : impl_(other.impl_), owns_impl_(false) {}
47 
48   // Assignment disabled
49   Heap& operator=(const Heap&) = delete;
50 
51   // Allocate size bytes
52   void* allocate(size_t size);
53 
54   // Deallocate allocation returned by allocate
55   void deallocate(void*);
56 
57   bool empty();
58 
59   static void deallocate(HeapImpl* impl, void* ptr);
60 
61   // Allocate a class of type T
62   template<class T>
allocate()63   T* allocate() {
64     return reinterpret_cast<T*>(allocate(sizeof(T)));
65   }
66 
67   // Comparators, copied objects will be equal
68   bool operator ==(const Heap& other) const {
69     return impl_ == other.impl_;
70   }
71   bool operator !=(const Heap& other) const {
72     return !(*this == other);
73   }
74 
75   // std::unique_ptr wrapper that allocates using allocate and deletes using
76   // deallocate
77   template<class T>
78   using unique_ptr = std::unique_ptr<T, std::function<void(void*)>>;
79 
80   template<class T, class... Args>
make_unique(Args &&...args)81   unique_ptr<T> make_unique(Args&&... args) {
82     HeapImpl* impl = impl_;
83     return unique_ptr<T>(new (allocate<T>()) T(std::forward<Args>(args)...),
84         [impl](void* ptr) {
85           reinterpret_cast<T*>(ptr)->~T();
86           deallocate(impl, ptr);
87         });
88   }
89 
90   // std::unique_ptr wrapper that allocates using allocate and deletes using
91   // deallocate
92   template<class T>
93   using shared_ptr = std::shared_ptr<T>;
94 
95   template<class T, class... Args>
96   shared_ptr<T> make_shared(Args&&... args);
97 
98 protected:
99   HeapImpl* impl_;
100   bool owns_impl_;
101 };
102 
103 // STLAllocator implements the std allocator interface on top of a Heap
104 template<typename T>
105 class STLAllocator {
106 public:
107   using value_type = T;
~STLAllocator()108   ~STLAllocator() {
109   }
110 
111   // Construct an STLAllocator on top of a Heap
STLAllocator(const Heap & heap)112   STLAllocator(const Heap& heap) :
113       heap_(heap) {
114   }
115 
116   // Rebind an STLAllocator from an another STLAllocator
117   template<typename U>
STLAllocator(const STLAllocator<U> & other)118   STLAllocator(const STLAllocator<U>& other) :
119       heap_(other.heap_) {
120   }
121 
122   STLAllocator(const STLAllocator&) = default;
123   STLAllocator<T>& operator=(const STLAllocator<T>&) = default;
124 
allocate(std::size_t n)125   T* allocate(std::size_t n) {
126     return reinterpret_cast<T*>(heap_.allocate(n * sizeof(T)));
127   }
128 
deallocate(T * ptr,std::size_t)129   void deallocate(T* ptr, std::size_t) {
130     heap_.deallocate(ptr);
131   }
132 
133   template<typename U>
134   bool operator ==(const STLAllocator<U>& other) const {
135     return heap_ == other.heap_;
136   }
137   template<typename U>
138   inline bool operator !=(const STLAllocator<U>& other) const {
139     return !(this == other);
140   }
141 
142   template<typename U>
143   friend class STLAllocator;
144 
145 protected:
146   Heap heap_;
147 };
148 
149 
150 // Allocator extends STLAllocator with some convenience methods for allocating
151 // a single object and for constructing unique_ptr and shared_ptr objects with
152 // appropriate deleters.
153 template<class T>
154 class Allocator : public STLAllocator<T> {
155  public:
~Allocator()156   ~Allocator() {}
157 
Allocator(const Heap & other)158   Allocator(const Heap& other) :
159       STLAllocator<T>(other) {
160   }
161 
162   template<typename U>
Allocator(const STLAllocator<U> & other)163   Allocator(const STLAllocator<U>& other) :
164       STLAllocator<T>(other) {
165   }
166 
167   Allocator(const Allocator&) = default;
168   Allocator<T>& operator=(const Allocator<T>&) = default;
169 
170   using STLAllocator<T>::allocate;
171   using STLAllocator<T>::deallocate;
172   using STLAllocator<T>::heap_;
173 
allocate()174   T* allocate() {
175     return STLAllocator<T>::allocate(1);
176   }
deallocate(void * ptr)177   void deallocate(void* ptr) {
178     heap_.deallocate(ptr);
179   }
180 
181   using shared_ptr = Heap::shared_ptr<T>;
182 
183   template<class... Args>
make_shared(Args &&...args)184   shared_ptr make_shared(Args&& ...args) {
185     return heap_.template make_shared<T>(std::forward<Args>(args)...);
186   }
187 
188   using unique_ptr = Heap::unique_ptr<T>;
189 
190   template<class... Args>
make_unique(Args &&...args)191   unique_ptr make_unique(Args&& ...args) {
192     return heap_.template make_unique<T>(std::forward<Args>(args)...);
193   }
194 };
195 
196 // std::unique_ptr wrapper that allocates using allocate and deletes using
197 // deallocate.  Implemented outside class definition in order to pass
198 // Allocator<T> to shared_ptr.
199 template<class T, class... Args>
make_shared(Args &&...args)200 inline Heap::shared_ptr<T> Heap::make_shared(Args&&... args) {
201   return std::allocate_shared<T, Allocator<T>, Args...>(Allocator<T>(*this),
202       std::forward<Args>(args)...);
203 }
204 
205 namespace allocator {
206 
207 template<class T>
208 using vector = std::vector<T, Allocator<T>>;
209 
210 template<class T>
211 using list = std::list<T, Allocator<T>>;
212 
213 template<class Key, class T, class Compare = std::less<Key>>
214 using map = std::map<Key, T, Compare, Allocator<std::pair<const Key, T>>>;
215 
216 template<class Key, class T, class Hash = std::hash<Key>, class KeyEqual = std::equal_to<Key>>
217 using unordered_map = std::unordered_map<Key, T, Hash, KeyEqual, Allocator<std::pair<const Key, T>>>;
218 
219 template<class Key, class Hash = std::hash<Key>, class KeyEqual = std::equal_to<Key>>
220 using unordered_set = std::unordered_set<Key, Hash, KeyEqual, Allocator<Key>>;
221 
222 template<class Key, class Compare = std::less<Key>>
223 using set = std::set<Key, Compare, Allocator<Key>>;
224 
225 using string = std::basic_string<char, std::char_traits<char>, Allocator<char>>;
226 }
227 
228 #endif
229