1 /* 2 * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #ifndef SHARE_UTILITIES_LINKEDLIST_HPP 26 #define SHARE_UTILITIES_LINKEDLIST_HPP 27 28 #include "memory/allocation.hpp" 29 30 /* 31 * The implementation of a generic linked list, which uses various 32 * backing storages, such as C heap, arena and resource, etc. 33 */ 34 35 36 // An entry in a linked list. It should use the same backing storage 37 // as the linked list that contains this entry. 38 template <class E> class LinkedListNode : public ResourceObj { 39 private: 40 E _data; // embedded content 41 LinkedListNode<E>* _next; // next entry 42 43 // Select member function 'bool U::equals(const U&) const' if 'U' is of class 44 // type. This works because of the "Substitution Failure Is Not An Error" 45 // (SFINAE) rule. Notice that this version of 'equal' will also be chosen for 46 // class types which don't define a corresponding 'equals()' method (and will 47 // result in a compilation error for them). It is not easily possible to 48 // specialize this 'equal()' function exclusively for class types which define 49 // the correct 'equals()' function because that function can be in a base 50 // class, a dependent base class or have a compatible but slightly different 51 // signature. 52 template <class U> equal(const U & a,const U & b,bool (U::* t)(const U &)const)53 static bool equal(const U& a, const U& b, bool (U::*t)(const U&) const) { 54 return a.equals(b); 55 } 56 57 template <class U> equal(const U & a,const U & b,...)58 static bool equal(const U& a, const U& b, ...) { 59 return a == b; 60 } 61 62 protected: LinkedListNode()63 LinkedListNode() : _next(NULL) { } 64 65 public: LinkedListNode(const E & e)66 LinkedListNode(const E& e): _data(e), _next(NULL) { } 67 set_next(LinkedListNode<E> * node)68 inline void set_next(LinkedListNode<E>* node) { _next = node; } next() const69 inline LinkedListNode<E> * next() const { return _next; } 70 data()71 E* data() { return &_data; } peek() const72 const E* peek() const { return &_data; } 73 equals(const E & t) const74 bool equals(const E& t) const { 75 return equal<E>(_data, t, NULL); 76 } 77 }; 78 79 // A linked list interface. It does not specify 80 // any storage type it uses, so all methods involving 81 // memory allocation or deallocation are pure virtual 82 template <class E> class LinkedList : public ResourceObj { 83 protected: 84 LinkedListNode<E>* _head; 85 NONCOPYABLE(LinkedList<E>); 86 87 public: LinkedList()88 LinkedList() : _head(NULL) { } ~LinkedList()89 virtual ~LinkedList() {} 90 set_head(LinkedListNode<E> * h)91 inline void set_head(LinkedListNode<E>* h) { _head = h; } head() const92 inline LinkedListNode<E>* head() const { return _head; } is_empty() const93 inline bool is_empty() const { return head() == NULL; } 94 size() const95 inline size_t size() const { 96 LinkedListNode<E>* p; 97 size_t count = 0; 98 for (p = head(); p != NULL; count++, p = p->next()); 99 return count; 100 } 101 102 // Move all entries from specified linked list to this one 103 virtual void move(LinkedList<E>* list) = 0; 104 105 // Add an entry to this linked list 106 virtual LinkedListNode<E>* add(const E& e) = 0; 107 // Add all entries from specified linked list to this one, 108 virtual void add(LinkedListNode<E>* node) = 0; 109 110 // Add a linked list to this linked list 111 virtual bool add(const LinkedList<E>* list) = 0; 112 113 // Search entry in the linked list 114 virtual LinkedListNode<E>* find_node(const E& e) = 0; 115 virtual E* find(const E& e) = 0; 116 117 // Insert entry to the linked list 118 virtual LinkedListNode<E>* insert_before(const E& e, LinkedListNode<E>* ref) = 0; 119 virtual LinkedListNode<E>* insert_after (const E& e, LinkedListNode<E>* ref) = 0; 120 121 // Remove entry from the linked list 122 virtual bool remove(const E& e) = 0; 123 virtual bool remove(LinkedListNode<E>* node) = 0; 124 virtual bool remove_before(LinkedListNode<E>* ref) = 0; 125 virtual bool remove_after(LinkedListNode<E>* ref) = 0; 126 unlink_head()127 LinkedListNode<E>* unlink_head() { 128 LinkedListNode<E>* h = this->head(); 129 if (h != NULL) { 130 this->set_head(h->next()); 131 } 132 return h; 133 } 134 135 DEBUG_ONLY(virtual ResourceObj::allocation_type storage_type() = 0;) 136 }; 137 138 // A linked list implementation. 139 // The linked list can be allocated in various type of memory: C heap, arena and resource area, etc. 140 template <class E, ResourceObj::allocation_type T = ResourceObj::C_HEAP, 141 MEMFLAGS F = mtNMT, AllocFailType alloc_failmode = AllocFailStrategy::RETURN_NULL> 142 class LinkedListImpl : public LinkedList<E> { 143 protected: 144 Arena* _arena; 145 public: LinkedListImpl()146 LinkedListImpl() : _arena(NULL) { } LinkedListImpl(Arena * a)147 LinkedListImpl(Arena* a) : _arena(a) { } 148 ~LinkedListImpl()149 virtual ~LinkedListImpl() { 150 clear(); 151 } 152 clear()153 virtual void clear() { 154 LinkedListNode<E>* p = this->head(); 155 this->set_head(NULL); 156 while (p != NULL) { 157 LinkedListNode<E>* to_delete = p; 158 p = p->next(); 159 delete_node(to_delete); 160 } 161 } 162 163 // Add an entry to the linked list add(const E & e)164 virtual LinkedListNode<E>* add(const E& e) { 165 LinkedListNode<E>* node = this->new_node(e); 166 if (node != NULL) { 167 this->add(node); 168 } 169 170 return node; 171 } 172 add(LinkedListNode<E> * node)173 virtual void add(LinkedListNode<E>* node) { 174 assert(node != NULL, "NULL pointer"); 175 node->set_next(this->head()); 176 this->set_head(node); 177 } 178 179 // Move a linked list to this linked list, both have to be allocated on the same 180 // storage type. move(LinkedList<E> * list)181 virtual void move(LinkedList<E>* list) { 182 assert(list->storage_type() == this->storage_type(), "Different storage type"); 183 LinkedListNode<E>* node = this->head(); 184 while (node != NULL && node->next() != NULL) { 185 node = node->next(); 186 } 187 if (node == NULL) { 188 this->set_head(list->head()); 189 } else { 190 node->set_next(list->head()); 191 } 192 // All entries are moved 193 list->set_head(NULL); 194 } 195 add(const LinkedList<E> * list)196 virtual bool add(const LinkedList<E>* list) { 197 LinkedListNode<E>* node = list->head(); 198 while (node != NULL) { 199 if (this->add(*node->peek()) == NULL) { 200 return false; 201 } 202 node = node->next(); 203 } 204 return true; 205 } 206 207 find_node(const E & e)208 virtual LinkedListNode<E>* find_node(const E& e) { 209 LinkedListNode<E>* p = this->head(); 210 while (p != NULL && !p->equals(e)) { 211 p = p->next(); 212 } 213 return p; 214 } 215 find(const E & e)216 E* find(const E& e) { 217 LinkedListNode<E>* node = find_node(e); 218 return (node == NULL) ? NULL : node->data(); 219 } 220 221 222 // Add an entry in front of the reference entry insert_before(const E & e,LinkedListNode<E> * ref_node)223 LinkedListNode<E>* insert_before(const E& e, LinkedListNode<E>* ref_node) { 224 LinkedListNode<E>* node = this->new_node(e); 225 if (node == NULL) return NULL; 226 if (ref_node == this->head()) { 227 node->set_next(ref_node); 228 this->set_head(node); 229 } else { 230 LinkedListNode<E>* p = this->head(); 231 while (p != NULL && p->next() != ref_node) { 232 p = p->next(); 233 } 234 assert(p != NULL, "ref_node not in the list"); 235 node->set_next(ref_node); 236 p->set_next(node); 237 } 238 return node; 239 } 240 241 // Add an entry behind the reference entry insert_after(const E & e,LinkedListNode<E> * ref_node)242 LinkedListNode<E>* insert_after(const E& e, LinkedListNode<E>* ref_node) { 243 LinkedListNode<E>* node = this->new_node(e); 244 if (node == NULL) return NULL; 245 node->set_next(ref_node->next()); 246 ref_node->set_next(node); 247 return node; 248 } 249 250 // Remove an entry from the linked list. 251 // Return true if the entry is successfully removed remove(const E & e)252 virtual bool remove(const E& e) { 253 LinkedListNode<E>* tmp = this->head(); 254 LinkedListNode<E>* prev = NULL; 255 256 while (tmp != NULL) { 257 if (tmp->equals(e)) { 258 return remove_after(prev); 259 } 260 prev = tmp; 261 tmp = tmp->next(); 262 } 263 return false; 264 } 265 266 // Remove the node after the reference entry remove_after(LinkedListNode<E> * prev)267 virtual bool remove_after(LinkedListNode<E>* prev) { 268 LinkedListNode<E>* to_delete; 269 if (prev == NULL) { 270 to_delete = this->unlink_head(); 271 } else { 272 to_delete = prev->next(); 273 if (to_delete != NULL) { 274 prev->set_next(to_delete->next()); 275 } 276 } 277 278 if (to_delete != NULL) { 279 delete_node(to_delete); 280 return true; 281 } 282 return false; 283 } 284 remove(LinkedListNode<E> * node)285 virtual bool remove(LinkedListNode<E>* node) { 286 LinkedListNode<E>* p = this->head(); 287 if (p == node) { 288 this->set_head(p->next()); 289 delete_node(node); 290 return true; 291 } 292 while (p != NULL && p->next() != node) { 293 p = p->next(); 294 } 295 if (p != NULL) { 296 p->set_next(node->next()); 297 delete_node(node); 298 return true; 299 } else { 300 return false; 301 } 302 } 303 remove_before(LinkedListNode<E> * ref)304 virtual bool remove_before(LinkedListNode<E>* ref) { 305 assert(ref != NULL, "NULL pointer"); 306 LinkedListNode<E>* p = this->head(); 307 LinkedListNode<E>* to_delete = NULL; // to be deleted 308 LinkedListNode<E>* prev = NULL; // node before the node to be deleted 309 while (p != NULL && p != ref) { 310 prev = to_delete; 311 to_delete = p; 312 p = p->next(); 313 } 314 if (p == NULL || to_delete == NULL) return false; 315 assert(to_delete->next() == ref, "Wrong node to delete"); 316 assert(prev == NULL || prev->next() == to_delete, 317 "Sanity check"); 318 if (prev == NULL) { 319 assert(to_delete == this->head(), "Must be head"); 320 this->set_head(to_delete->next()); 321 } else { 322 prev->set_next(to_delete->next()); 323 } 324 delete_node(to_delete); 325 return true; 326 } 327 328 DEBUG_ONLY(ResourceObj::allocation_type storage_type() { return T; }) 329 protected: 330 // Create new linked list node object in specified storage new_node(const E & e) const331 LinkedListNode<E>* new_node(const E& e) const { 332 switch(T) { 333 case ResourceObj::ARENA: { 334 assert(_arena != NULL, "Arena not set"); 335 return new(_arena) LinkedListNode<E>(e); 336 } 337 case ResourceObj::RESOURCE_AREA: 338 case ResourceObj::C_HEAP: { 339 if (alloc_failmode == AllocFailStrategy::RETURN_NULL) { 340 return new(std::nothrow, T, F) LinkedListNode<E>(e); 341 } else { 342 return new(T, F) LinkedListNode<E>(e); 343 } 344 } 345 default: 346 ShouldNotReachHere(); 347 } 348 return NULL; 349 } 350 351 // Delete linked list node object delete_node(LinkedListNode<E> * node)352 void delete_node(LinkedListNode<E>* node) { 353 if (T == ResourceObj::C_HEAP) { 354 delete node; 355 } 356 } 357 }; 358 359 // Sorted linked list. The linked list maintains sorting order specified by the comparison 360 // function 361 template <class E, int (*FUNC)(const E&, const E&), 362 ResourceObj::allocation_type T = ResourceObj::C_HEAP, 363 MEMFLAGS F = mtNMT, AllocFailType alloc_failmode = AllocFailStrategy::RETURN_NULL> 364 class SortedLinkedList : public LinkedListImpl<E, T, F, alloc_failmode> { 365 public: SortedLinkedList()366 SortedLinkedList() { } SortedLinkedList(Arena * a)367 SortedLinkedList(Arena* a) : LinkedListImpl<E, T, F, alloc_failmode>(a) { } 368 add(const E & e)369 virtual LinkedListNode<E>* add(const E& e) { 370 return LinkedListImpl<E, T, F, alloc_failmode>::add(e); 371 } 372 move(LinkedList<E> * list)373 virtual void move(LinkedList<E>* list) { 374 assert(list->storage_type() == this->storage_type(), "Different storage type"); 375 LinkedListNode<E>* node; 376 while ((node = list->unlink_head()) != NULL) { 377 this->add(node); 378 } 379 assert(list->is_empty(), "All entries are moved"); 380 } 381 add(LinkedListNode<E> * node)382 virtual void add(LinkedListNode<E>* node) { 383 assert(node != NULL, "NULL pointer"); 384 LinkedListNode<E>* tmp = this->head(); 385 LinkedListNode<E>* prev = NULL; 386 387 int cmp_val; 388 while (tmp != NULL) { 389 cmp_val = FUNC(*tmp->peek(), *node->peek()); 390 if (cmp_val >= 0) { 391 break; 392 } 393 prev = tmp; 394 tmp = tmp->next(); 395 } 396 397 if (prev != NULL) { 398 node->set_next(prev->next()); 399 prev->set_next(node); 400 } else { 401 node->set_next(this->head()); 402 this->set_head(node); 403 } 404 } 405 add(const LinkedList<E> * list)406 virtual bool add(const LinkedList<E>* list) { 407 return LinkedListImpl<E, T, F, alloc_failmode>::add(list); 408 } 409 find_node(const E & e)410 virtual LinkedListNode<E>* find_node(const E& e) { 411 LinkedListNode<E>* p = this->head(); 412 413 while (p != NULL) { 414 int comp_val = FUNC(*p->peek(), e); 415 if (comp_val == 0) { 416 return p; 417 } else if (comp_val > 0) { 418 return NULL; 419 } 420 p = p->next(); 421 } 422 return NULL; 423 } 424 }; 425 426 // Iterates all entries in the list 427 template <class E> class LinkedListIterator : public StackObj { 428 private: 429 mutable LinkedListNode<E>* _p; 430 431 public: LinkedListIterator(LinkedListNode<E> * head)432 LinkedListIterator(LinkedListNode<E>* head) : _p(head) {} 433 is_empty() const434 bool is_empty() const { return _p == NULL; } 435 next()436 E* next() { 437 if (_p == NULL) return NULL; 438 E* e = _p->data(); 439 _p = _p->next(); 440 return e; 441 } 442 next() const443 const E* next() const { 444 if (_p == NULL) return NULL; 445 const E* e = _p->peek(); 446 _p = _p->next(); 447 return e; 448 } 449 }; 450 451 #endif // SHARE_UTILITIES_LINKEDLIST_HPP 452