changeset 60217:582e5f2661c3

8239066: make LinkedList<T> more generic Reviewed-by: phh, simonis
author xliu
date Wed, 26 Feb 2020 12:35:43 +0100
parents 61ee15b9a1ac
children c27d95f72ba8
files src/hotspot/share/utilities/linkedlist.hpp test/hotspot/gtest/utilities/test_linkedlist.cpp
diffstat 2 files changed, 118 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/utilities/linkedlist.hpp	Mon Feb 24 09:59:31 2020 +0100
+++ b/src/hotspot/share/utilities/linkedlist.hpp	Wed Feb 26 12:35:43 2020 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -40,6 +40,25 @@
   E                       _data;  // embedded content
   LinkedListNode<E>*      _next;  // next entry
 
+  // Select member function 'bool U::equals(const U&) const' if 'U' is of class
+  // type. This works because of the "Substitution Failure Is Not An Error"
+  // (SFINAE) rule. Notice that this version of 'equal' will also be chosen for
+  // class types which don't define a corresponding 'equals()' method (and will
+  // result in a compilation error for them). It is not easily possible to
+  // specialize this 'equal()' function exclusively for class types which define
+  // the correct 'equals()' function because that function can be in a base
+  // class, a dependent base class or have a compatible but slightly different
+  // signature.
+  template <class U>
+  static bool equal(const U& a, const U& b, bool (U::*t)(const U&) const) {
+    return a.equals(b);
+  }
+
+  template <class U>
+  static bool equal(const U& a, const U& b, ...) {
+    return a == b;
+  }
+
  protected:
   LinkedListNode() : _next(NULL) { }
 
@@ -51,6 +70,10 @@
 
   E*  data() { return &_data; }
   const E* peek() const { return &_data; }
+
+  bool equals(const E& t) const {
+    return equal<E>(_data, t, NULL);
+  }
 };
 
 // A linked list interface. It does not specify
@@ -59,9 +82,11 @@
 template <class E> class LinkedList : public ResourceObj {
  protected:
   LinkedListNode<E>*    _head;
+  NONCOPYABLE(LinkedList<E>);
 
  public:
   LinkedList() : _head(NULL) { }
+  virtual ~LinkedList() {}
 
   inline void set_head(LinkedListNode<E>* h) { _head = h; }
   inline LinkedListNode<E>* head() const     { return _head; }
@@ -182,7 +207,7 @@
 
   virtual LinkedListNode<E>* find_node(const E& e) {
     LinkedListNode<E>* p = this->head();
-    while (p != NULL && !p->peek()->equals(e)) {
+    while (p != NULL && !p->equals(e)) {
       p = p->next();
     }
     return p;
@@ -229,7 +254,7 @@
      LinkedListNode<E>* prev = NULL;
 
      while (tmp != NULL) {
-       if (tmp->peek()->equals(e)) {
+       if (tmp->equals(e)) {
          return remove_after(prev);
        }
        prev = tmp;
@@ -401,16 +426,21 @@
 // Iterates all entries in the list
 template <class E> class LinkedListIterator : public StackObj {
  private:
-  LinkedListNode<E>* _p;
-  bool               _is_empty;
+  mutable LinkedListNode<E>* _p;
+
  public:
-  LinkedListIterator(LinkedListNode<E>* head) : _p(head) {
-    _is_empty = (head == NULL);
+  LinkedListIterator(LinkedListNode<E>* head) : _p(head) {}
+
+  bool is_empty() const { return _p == NULL; }
+
+  E* next() {
+    if (_p == NULL) return NULL;
+    E* e = _p->data();
+    _p = _p->next();
+    return e;
   }
 
-  bool is_empty() const { return _is_empty; }
-
-  const E* next() {
+  const E* next() const {
     if (_p == NULL) return NULL;
     const E* e = _p->peek();
     _p = _p->next();
--- a/test/hotspot/gtest/utilities/test_linkedlist.cpp	Mon Feb 24 09:59:31 2020 +0100
+++ b/test/hotspot/gtest/utilities/test_linkedlist.cpp	Wed Feb 26 12:35:43 2020 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -58,7 +58,7 @@
   }
 }
 
-const Integer one(1), two(2), three(3), four(4), five(5), six(6);
+const Integer one(1), two(2), three(3), four(4), five(5), six(6), notfound(404);
 
 // Test regular linked list
 TEST(LinkedList, simple) {
@@ -85,6 +85,82 @@
   check_list_values(expected, &ll);
 }
 
+TEST(LinkedList, generic) {
+  LinkedListImpl<int> il;
+  const int N = 100;
+  for (int i=0; i<N; ++i) {
+    il.add(i);
+  }
+  EXPECT_EQ(il.size(), (size_t)N);
+
+  const LinkedListIterator<int> cit(il.head());
+  for (int i=N-1; i>=0; --i) {
+    const int* e = cit.next();
+    EXPECT_EQ(*e, i);
+  }
+  EXPECT_TRUE(cit.is_empty());
+  EXPECT_EQ(il.size(), (size_t)N);
+  EXPECT_EQ(*(il.head()->peek()), N-1);
+
+  typedef LinkedListImpl<Integer, ResourceObj::C_HEAP, mtTest> list_t;
+  LinkedList<Integer>* list = new(ResourceObj::C_HEAP, mtTest) list_t();
+  list->add(Integer(1));
+  list->add(Integer(2));
+  EXPECT_EQ(list->size(), (size_t)2);
+  list->~LinkedList<Integer>();
+  EXPECT_EQ(list->size(), (size_t)0);
+
+  // copyable
+  //list_t a;
+  //a.add(Integer(1));
+  //list_t b(a);
+  //EXPECT_EQ(b.size(), (size_t)1);
+  //EXPECT_TRUE(b.head()->peek()->equals(Integer(1)));
+
+  list_t lifo, dummy;
+  const Integer* e;
+  lifo.add(one);
+  lifo.add(two);
+  LinkedListIterator<Integer> it(lifo.head());
+
+  EXPECT_FALSE(it.is_empty());
+  // pop 2
+  e = it.next();
+  EXPECT_TRUE(e->equals(two));
+  EXPECT_FALSE(it.is_empty());
+  // pop 1
+  e = it.next();
+  EXPECT_TRUE(e->equals(one));
+  //empty
+  EXPECT_TRUE(it.is_empty());
+
+  LinkedListIterator<Integer> it2(dummy.head());
+  EXPECT_TRUE(it2.is_empty());
+  EXPECT_EQ(it2.next(), (Integer* )NULL);
+}
+
+TEST(LinkedList, algorithm) {
+  LinkedListImpl<int> il;
+  il.add(1);
+  il.add(2);
+  il.add(3);
+  EXPECT_EQ(*il.find(1), 1);
+  EXPECT_EQ(il.find(404), (int* )NULL);
+  EXPECT_TRUE(il.remove(1));
+  EXPECT_FALSE(il.remove(404));
+
+  LinkedListImpl<Integer, ResourceObj::C_HEAP, mtTest> ll;
+  ll.add(one);
+
+  EXPECT_TRUE(ll.find(one));
+  EXPECT_FALSE(ll.find(notfound));
+
+  EXPECT_TRUE(ll.remove(one));
+  EXPECT_FALSE(ll.find(one));
+  EXPECT_FALSE(ll.remove(notfound));
+  EXPECT_FALSE(ll.find(notfound));
+}
+
 // Test sorted linked list
 TEST(SortedLinkedList, simple) {
   LinkedListImpl<Integer, ResourceObj::C_HEAP, mtTest> ll;