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