1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in 12 * the documentation and/or other materials provided with the 13 * distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #pragma once 30 31 #include <android-base/macros.h> 32 33 template<typename T> 34 struct LinkedListEntry { 35 LinkedListEntry<T>* next; 36 T* element; 37 }; 38 39 // ForwardInputIterator 40 template<typename T> 41 class LinkedListIterator { 42 public: LinkedListIterator()43 LinkedListIterator() : entry_(nullptr) {} LinkedListIterator(const LinkedListIterator<T> & that)44 LinkedListIterator(const LinkedListIterator<T>& that) : entry_(that.entry_) {} LinkedListIterator(LinkedListEntry<T> * entry)45 explicit LinkedListIterator(LinkedListEntry<T>* entry) : entry_(entry) {} 46 47 LinkedListIterator<T>& operator=(const LinkedListIterator<T>& that) { 48 entry_ = that.entry_; 49 return *this; 50 } 51 52 LinkedListIterator<T>& operator++() { 53 entry_ = entry_->next; 54 return *this; 55 } 56 57 T* const operator*() { 58 return entry_->element; 59 } 60 61 bool operator==(const LinkedListIterator<T>& that) const { 62 return entry_ == that.entry_; 63 } 64 65 bool operator!=(const LinkedListIterator<T>& that) const { 66 return entry_ != that.entry_; 67 } 68 69 private: 70 LinkedListEntry<T> *entry_; 71 }; 72 73 /* 74 * Represents linked list of objects of type T 75 */ 76 template<typename T, typename Allocator> 77 class LinkedList { 78 public: 79 typedef LinkedListIterator<T> iterator; 80 typedef T* value_type; 81 82 // Allocating the head/tail fields separately from the LinkedList struct saves memory in the 83 // Zygote (e.g. because adding an soinfo to a namespace doesn't dirty the page containing the 84 // soinfo). 85 struct LinkedListHeader { 86 LinkedListEntry<T>* head; 87 LinkedListEntry<T>* tail; 88 }; 89 90 // The allocator returns a LinkedListEntry<T>* but we want to treat it as a LinkedListHeader 91 // struct instead. 92 static_assert(sizeof(LinkedListHeader) == sizeof(LinkedListEntry<T>)); 93 static_assert(alignof(LinkedListHeader) == alignof(LinkedListEntry<T>)); 94 LinkedList()95 constexpr LinkedList() : header_(nullptr) {} ~LinkedList()96 ~LinkedList() { 97 clear(); 98 if (header_ != nullptr) { 99 Allocator::free(reinterpret_cast<LinkedListEntry<T>*>(header_)); 100 } 101 } 102 LinkedList(LinkedList && that)103 LinkedList(LinkedList&& that) noexcept { 104 this->header_ = that.header_; 105 that.header_ = nullptr; 106 } 107 empty()108 bool empty() const { 109 return header_ == nullptr || header_->head == nullptr; 110 } 111 push_front(T * const element)112 void push_front(T* const element) { 113 alloc_header(); 114 LinkedListEntry<T>* new_entry = Allocator::alloc(); 115 new_entry->next = header_->head; 116 new_entry->element = element; 117 header_->head = new_entry; 118 if (header_->tail == nullptr) { 119 header_->tail = new_entry; 120 } 121 } 122 push_back(T * const element)123 void push_back(T* const element) { 124 alloc_header(); 125 LinkedListEntry<T>* new_entry = Allocator::alloc(); 126 new_entry->next = nullptr; 127 new_entry->element = element; 128 if (header_->tail == nullptr) { 129 header_->tail = header_->head = new_entry; 130 } else { 131 header_->tail->next = new_entry; 132 header_->tail = new_entry; 133 } 134 } 135 pop_front()136 T* pop_front() { 137 if (empty()) return nullptr; 138 139 LinkedListEntry<T>* entry = header_->head; 140 T* element = entry->element; 141 header_->head = entry->next; 142 Allocator::free(entry); 143 144 if (header_->head == nullptr) { 145 header_->tail = nullptr; 146 } 147 148 return element; 149 } 150 front()151 T* front() const { 152 return empty() ? nullptr : header_->head->element; 153 } 154 clear()155 void clear() { 156 if (empty()) return; 157 158 while (header_->head != nullptr) { 159 LinkedListEntry<T>* p = header_->head; 160 header_->head = header_->head->next; 161 Allocator::free(p); 162 } 163 164 header_->tail = nullptr; 165 } 166 167 template<typename F> for_each(F action)168 void for_each(F action) const { 169 visit([&] (T* si) { 170 action(si); 171 return true; 172 }); 173 } 174 175 template<typename F> visit(F action)176 bool visit(F action) const { 177 for (LinkedListEntry<T>* e = head(); e != nullptr; e = e->next) { 178 if (!action(e->element)) { 179 return false; 180 } 181 } 182 return true; 183 } 184 185 template<typename F> remove_if(F predicate)186 void remove_if(F predicate) { 187 if (empty()) return; 188 for (LinkedListEntry<T>* e = header_->head, *p = nullptr; e != nullptr;) { 189 if (predicate(e->element)) { 190 LinkedListEntry<T>* next = e->next; 191 if (p == nullptr) { 192 header_->head = next; 193 } else { 194 p->next = next; 195 } 196 197 if (header_->tail == e) { 198 header_->tail = p; 199 } 200 201 Allocator::free(e); 202 203 e = next; 204 } else { 205 p = e; 206 e = e->next; 207 } 208 } 209 } 210 remove(T * element)211 void remove(T* element) { 212 remove_if([&](T* e) { 213 return e == element; 214 }); 215 } 216 217 template<typename F> find_if(F predicate)218 T* find_if(F predicate) const { 219 for (LinkedListEntry<T>* e = head(); e != nullptr; e = e->next) { 220 if (predicate(e->element)) { 221 return e->element; 222 } 223 } 224 225 return nullptr; 226 } 227 begin()228 iterator begin() const { 229 return iterator(head()); 230 } 231 end()232 iterator end() const { 233 return iterator(nullptr); 234 } 235 find(T * value)236 iterator find(T* value) const { 237 for (LinkedListEntry<T>* e = head(); e != nullptr; e = e->next) { 238 if (e->element == value) { 239 return iterator(e); 240 } 241 } 242 243 return end(); 244 } 245 copy_to_array(T * array[],size_t array_length)246 size_t copy_to_array(T* array[], size_t array_length) const { 247 size_t sz = 0; 248 for (LinkedListEntry<T>* e = head(); sz < array_length && e != nullptr; e = e->next) { 249 array[sz++] = e->element; 250 } 251 252 return sz; 253 } 254 contains(const T * el)255 bool contains(const T* el) const { 256 for (LinkedListEntry<T>* e = head(); e != nullptr; e = e->next) { 257 if (e->element == el) { 258 return true; 259 } 260 } 261 return false; 262 } 263 make_list(T * const element)264 static LinkedList make_list(T* const element) { 265 LinkedList<T, Allocator> one_element_list; 266 one_element_list.push_back(element); 267 return one_element_list; 268 } 269 size()270 size_t size() const { 271 size_t result = 0; 272 for_each([&](T*) { ++result; }); 273 return result; 274 } 275 276 private: alloc_header()277 void alloc_header() { 278 if (header_ == nullptr) { 279 header_ = reinterpret_cast<LinkedListHeader*>(Allocator::alloc()); 280 header_->head = header_->tail = nullptr; 281 } 282 } 283 head()284 LinkedListEntry<T>* head() const { 285 return header_ != nullptr ? header_->head : nullptr; 286 } 287 288 LinkedListHeader* header_; 289 DISALLOW_COPY_AND_ASSIGN(LinkedList); 290 }; 291