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 31namespace android { 32 33extern std::atomic<int> heap_count; 34 35class HeapImpl; 36 37template <typename T> 38class Allocator; 39 40// Non-templated class that implements wraps HeapImpl to keep 41// implementation out of the header file 42class 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 101template <typename T> 102class 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. 144template <class T> 145class 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. 186template <class T, class... Args> 187inline 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 192namespace allocator { 193 194template <class T> 195using vector = std::vector<T, Allocator<T>>; 196 197template <class T> 198using list = std::list<T, Allocator<T>>; 199 200template <class Key, class T, class Compare = std::less<Key>> 201using map = std::map<Key, T, Compare, Allocator<std::pair<const Key, T>>>; 202 203template <class Key, class T, class Hash = std::hash<Key>, class KeyEqual = std::equal_to<Key>> 204using unordered_map = 205 std::unordered_map<Key, T, Hash, KeyEqual, Allocator<std::pair<const Key, T>>>; 206 207template <class Key, class Hash = std::hash<Key>, class KeyEqual = std::equal_to<Key>> 208using unordered_set = std::unordered_set<Key, Hash, KeyEqual, Allocator<Key>>; 209 210template <class Key, class Compare = std::less<Key>> 211using set = std::set<Key, Compare, Allocator<Key>>; 212 213using string = std::basic_string<char, std::char_traits<char>, Allocator<char>>; 214} 215 216} // namespace android 217 218#endif 219