|  | /* | 
|  | * Copyright (C) 2016 The Android Open Source Project | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | * you may not use this file except in compliance with the License. | 
|  | * You may obtain a copy of the License at | 
|  | * | 
|  | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | * See the License for the specific language governing permissions and | 
|  | * limitations under the License. | 
|  | */ | 
|  |  | 
|  | #ifndef LIBMEMUNREACHABLE_ALLOCATOR_H_ | 
|  | #define LIBMEMUNREACHABLE_ALLOCATOR_H_ | 
|  |  | 
|  | #include <atomic> | 
|  | #include <cstddef> | 
|  | #include <functional> | 
|  | #include <list> | 
|  | #include <map> | 
|  | #include <memory> | 
|  | #include <set> | 
|  | #include <unordered_map> | 
|  | #include <unordered_set> | 
|  | #include <vector> | 
|  |  | 
|  | namespace android { | 
|  |  | 
|  | extern std::atomic<int> heap_count; | 
|  |  | 
|  | class HeapImpl; | 
|  |  | 
|  | template <typename T> | 
|  | class Allocator; | 
|  |  | 
|  | // Non-templated class that implements wraps HeapImpl to keep | 
|  | // implementation out of the header file | 
|  | class Heap { | 
|  | public: | 
|  | Heap(); | 
|  | ~Heap(); | 
|  |  | 
|  | // Copy constructor that does not take ownership of impl_ | 
|  | Heap(const Heap& other) : impl_(other.impl_), owns_impl_(false) {} | 
|  |  | 
|  | // Assignment disabled | 
|  | Heap& operator=(const Heap&) = delete; | 
|  |  | 
|  | // Allocate size bytes | 
|  | void* allocate(size_t size); | 
|  |  | 
|  | // Deallocate allocation returned by allocate | 
|  | void deallocate(void*); | 
|  |  | 
|  | bool empty(); | 
|  |  | 
|  | static void deallocate(HeapImpl* impl, void* ptr); | 
|  |  | 
|  | // Allocate a class of type T | 
|  | template <class T> | 
|  | T* allocate() { | 
|  | return reinterpret_cast<T*>(allocate(sizeof(T))); | 
|  | } | 
|  |  | 
|  | // Comparators, copied objects will be equal | 
|  | bool operator==(const Heap& other) const { return impl_ == other.impl_; } | 
|  | bool operator!=(const Heap& other) const { return !(*this == other); } | 
|  |  | 
|  | // std::unique_ptr wrapper that allocates using allocate and deletes using | 
|  | // deallocate | 
|  | template <class T> | 
|  | using unique_ptr = std::unique_ptr<T, std::function<void(void*)>>; | 
|  |  | 
|  | template <class T, class... Args> | 
|  | unique_ptr<T> make_unique(Args&&... args) { | 
|  | HeapImpl* impl = impl_; | 
|  | return unique_ptr<T>(new (allocate<T>()) T(std::forward<Args>(args)...), [impl](void* ptr) { | 
|  | reinterpret_cast<T*>(ptr)->~T(); | 
|  | deallocate(impl, ptr); | 
|  | }); | 
|  | } | 
|  |  | 
|  | // std::unique_ptr wrapper that allocates using allocate and deletes using | 
|  | // deallocate | 
|  | template <class T> | 
|  | using shared_ptr = std::shared_ptr<T>; | 
|  |  | 
|  | template <class T, class... Args> | 
|  | shared_ptr<T> make_shared(Args&&... args); | 
|  |  | 
|  | protected: | 
|  | HeapImpl* impl_; | 
|  | bool owns_impl_; | 
|  | }; | 
|  |  | 
|  | // STLAllocator implements the std allocator interface on top of a Heap | 
|  | template <typename T> | 
|  | class STLAllocator { | 
|  | public: | 
|  | using value_type = T; | 
|  | ~STLAllocator() {} | 
|  |  | 
|  | // Construct an STLAllocator on top of a Heap | 
|  | STLAllocator(const Heap& heap) | 
|  | :  // NOLINT, implicit | 
|  | heap_(heap) {} | 
|  |  | 
|  | // Rebind an STLAllocator from an another STLAllocator | 
|  | template <typename U> | 
|  | STLAllocator(const STLAllocator<U>& other) | 
|  | :  // NOLINT, implicit | 
|  | heap_(other.heap_) {} | 
|  |  | 
|  | STLAllocator(const STLAllocator&) = default; | 
|  | STLAllocator<T>& operator=(const STLAllocator<T>&) = default; | 
|  |  | 
|  | T* allocate(std::size_t n) { return reinterpret_cast<T*>(heap_.allocate(n * sizeof(T))); } | 
|  |  | 
|  | void deallocate(T* ptr, std::size_t) { heap_.deallocate(ptr); } | 
|  |  | 
|  | template <typename U> | 
|  | bool operator==(const STLAllocator<U>& other) const { | 
|  | return heap_ == other.heap_; | 
|  | } | 
|  | template <typename U> | 
|  | inline bool operator!=(const STLAllocator<U>& other) const { | 
|  | return !(this == other); | 
|  | } | 
|  |  | 
|  | template <typename U> | 
|  | friend class STLAllocator; | 
|  |  | 
|  | protected: | 
|  | Heap heap_; | 
|  | }; | 
|  |  | 
|  | // Allocator extends STLAllocator with some convenience methods for allocating | 
|  | // a single object and for constructing unique_ptr and shared_ptr objects with | 
|  | // appropriate deleters. | 
|  | template <class T> | 
|  | class Allocator : public STLAllocator<T> { | 
|  | public: | 
|  | ~Allocator() {} | 
|  |  | 
|  | Allocator(const Heap& other) | 
|  | :  // NOLINT, implicit | 
|  | STLAllocator<T>(other) {} | 
|  |  | 
|  | template <typename U> | 
|  | Allocator(const STLAllocator<U>& other) | 
|  | :  // NOLINT, implicit | 
|  | STLAllocator<T>(other) {} | 
|  |  | 
|  | Allocator(const Allocator&) = default; | 
|  | Allocator<T>& operator=(const Allocator<T>&) = default; | 
|  |  | 
|  | using STLAllocator<T>::allocate; | 
|  | using STLAllocator<T>::deallocate; | 
|  | using STLAllocator<T>::heap_; | 
|  |  | 
|  | T* allocate() { return STLAllocator<T>::allocate(1); } | 
|  | void deallocate(void* ptr) { heap_.deallocate(ptr); } | 
|  |  | 
|  | using shared_ptr = Heap::shared_ptr<T>; | 
|  |  | 
|  | template <class... Args> | 
|  | shared_ptr make_shared(Args&&... args) { | 
|  | return heap_.template make_shared<T>(std::forward<Args>(args)...); | 
|  | } | 
|  |  | 
|  | using unique_ptr = Heap::unique_ptr<T>; | 
|  |  | 
|  | template <class... Args> | 
|  | unique_ptr make_unique(Args&&... args) { | 
|  | return heap_.template make_unique<T>(std::forward<Args>(args)...); | 
|  | } | 
|  | }; | 
|  |  | 
|  | // std::unique_ptr wrapper that allocates using allocate and deletes using | 
|  | // deallocate.  Implemented outside class definition in order to pass | 
|  | // Allocator<T> to shared_ptr. | 
|  | template <class T, class... Args> | 
|  | inline Heap::shared_ptr<T> Heap::make_shared(Args&&... args) { | 
|  | return std::allocate_shared<T, Allocator<T>, Args...>(Allocator<T>(*this), | 
|  | std::forward<Args>(args)...); | 
|  | } | 
|  |  | 
|  | namespace allocator { | 
|  |  | 
|  | template <class T> | 
|  | using vector = std::vector<T, Allocator<T>>; | 
|  |  | 
|  | template <class T> | 
|  | using list = std::list<T, Allocator<T>>; | 
|  |  | 
|  | template <class Key, class T, class Compare = std::less<Key>> | 
|  | using map = std::map<Key, T, Compare, Allocator<std::pair<const Key, T>>>; | 
|  |  | 
|  | template <class Key, class T, class Hash = std::hash<Key>, class KeyEqual = std::equal_to<Key>> | 
|  | using unordered_map = | 
|  | std::unordered_map<Key, T, Hash, KeyEqual, Allocator<std::pair<const Key, T>>>; | 
|  |  | 
|  | template <class Key, class Hash = std::hash<Key>, class KeyEqual = std::equal_to<Key>> | 
|  | using unordered_set = std::unordered_set<Key, Hash, KeyEqual, Allocator<Key>>; | 
|  |  | 
|  | template <class Key, class Compare = std::less<Key>> | 
|  | using set = std::set<Key, Compare, Allocator<Key>>; | 
|  |  | 
|  | using string = std::basic_string<char, std::char_traits<char>, Allocator<char>>; | 
|  | } | 
|  |  | 
|  | }  // namespace android | 
|  |  | 
|  | #endif |