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