From b08595d8443bbfb141685dc5eda7c58a34738048 Mon Sep 17 00:00:00 2001 From: Xin Liu Date: Wed, 26 Feb 2020 12:35:43 +0100 Subject: [PATCH] 8239066: make LinkedList more generic Reviewed-by: phh, simonis --- src/hotspot/share/utilities/linkedlist.hpp | 50 +++++++++--- .../gtest/utilities/test_linkedlist.cpp | 80 ++++++++++++++++++- 2 files changed, 118 insertions(+), 12 deletions(-) diff --git a/src/hotspot/share/utilities/linkedlist.hpp b/src/hotspot/share/utilities/linkedlist.hpp index 6c130cbd69e..16ee6a844fa 100644 --- a/src/hotspot/share/utilities/linkedlist.hpp +++ b/src/hotspot/share/utilities/linkedlist.hpp @@ -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 @@ template class LinkedListNode : public ResourceObj { E _data; // embedded content LinkedListNode* _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 + static bool equal(const U& a, const U& b, bool (U::*t)(const U&) const) { + return a.equals(b); + } + + template + static bool equal(const U& a, const U& b, ...) { + return a == b; + } + protected: LinkedListNode() : _next(NULL) { } @@ -51,6 +70,10 @@ template class LinkedListNode : public ResourceObj { E* data() { return &_data; } const E* peek() const { return &_data; } + + bool equals(const E& t) const { + return equal(_data, t, NULL); + } }; // A linked list interface. It does not specify @@ -59,9 +82,11 @@ template class LinkedListNode : public ResourceObj { template class LinkedList : public ResourceObj { protected: LinkedListNode* _head; + NONCOPYABLE(LinkedList); public: LinkedList() : _head(NULL) { } + virtual ~LinkedList() {} inline void set_head(LinkedListNode* h) { _head = h; } inline LinkedListNode* head() const { return _head; } @@ -182,7 +207,7 @@ template * find_node(const E& e) { LinkedListNode* 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 @@ template * prev = NULL; while (tmp != NULL) { - if (tmp->peek()->equals(e)) { + if (tmp->equals(e)) { return remove_after(prev); } prev = tmp; @@ -401,16 +426,21 @@ template class LinkedListIterator : public StackObj { private: - LinkedListNode* _p; - bool _is_empty; + mutable LinkedListNode* _p; + public: - LinkedListIterator(LinkedListNode* head) : _p(head) { - _is_empty = (head == NULL); + LinkedListIterator(LinkedListNode* 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(); diff --git a/test/hotspot/gtest/utilities/test_linkedlist.cpp b/test/hotspot/gtest/utilities/test_linkedlist.cpp index 471c4421f93..6ce1cf95d83 100644 --- a/test/hotspot/gtest/utilities/test_linkedlist.cpp +++ b/test/hotspot/gtest/utilities/test_linkedlist.cpp @@ -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 @@ static void check_list_values(const int* expected, const LinkedList* li } } -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 @@ TEST(LinkedList, simple) { check_list_values(expected, &ll); } +TEST(LinkedList, generic) { + LinkedListImpl il; + const int N = 100; + for (int i=0; i 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 list_t; + LinkedList* 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(); + 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 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 it2(dummy.head()); + EXPECT_TRUE(it2.is_empty()); + EXPECT_EQ(it2.next(), (Integer* )NULL); +} + +TEST(LinkedList, algorithm) { + LinkedListImpl 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 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 ll;