/* * 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> 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) : heap_(heap) { } // Rebind an STLAllocator from an another STLAllocator template<typename U> STLAllocator(const STLAllocator<U>& other) : 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) : STLAllocator<T>(other) { } template<typename U> Allocator(const STLAllocator<U>& other) : 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>>; } #endif