Home | History | Annotate | Download | only in libmemunreachable
      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