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_ 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> 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> 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; 108 ~STLAllocator() { 109 } 110 111 // Construct an STLAllocator on top of a Heap 112 STLAllocator(const Heap& heap) : 113 heap_(heap) { 114 } 115 116 // Rebind an STLAllocator from an another STLAllocator 117 template<typename U> 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 125 T* allocate(std::size_t n) { 126 return reinterpret_cast<T*>(heap_.allocate(n * sizeof(T))); 127 } 128 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: 156 ~Allocator() {} 157 158 Allocator(const Heap& other) : 159 STLAllocator<T>(other) { 160 } 161 162 template<typename U> 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 174 T* allocate() { 175 return STLAllocator<T>::allocate(1); 176 } 177 void deallocate(void* ptr) { 178 heap_.deallocate(ptr); 179 } 180 181 using shared_ptr = Heap::shared_ptr<T>; 182 183 template<class... 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> 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> 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