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