Skip to content

Commit

Permalink
8239066: make LinkedList<T> more generic
Browse files Browse the repository at this point in the history
Reviewed-by: phh, simonis
  • Loading branch information
Xin Liu committed Feb 26, 2020
1 parent dd393fa commit b08595d
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 12 deletions.
50 changes: 40 additions & 10 deletions 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
Expand Down Expand Up @@ -40,6 +40,25 @@ template <class E> class LinkedListNode : public ResourceObj {
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) { }

Expand All @@ -51,6 +70,10 @@ template <class E> class LinkedListNode : public ResourceObj {

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
Expand All @@ -59,9 +82,11 @@ template <class E> class LinkedListNode : public ResourceObj {
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; }
Expand Down Expand Up @@ -182,7 +207,7 @@ template <class E, ResourceObj::allocation_type T = ResourceObj::C_HEAP,

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;
Expand Down Expand Up @@ -229,7 +254,7 @@ template <class E, ResourceObj::allocation_type T = ResourceObj::C_HEAP,
LinkedListNode<E>* prev = NULL;

while (tmp != NULL) {
if (tmp->peek()->equals(e)) {
if (tmp->equals(e)) {
return remove_after(prev);
}
prev = tmp;
Expand Down Expand Up @@ -401,16 +426,21 @@ template <class E, int (*FUNC)(const E&, const E&),
// 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; }

bool is_empty() const { return _is_empty; }
E* next() {
if (_p == NULL) return NULL;
E* e = _p->data();
_p = _p->next();
return e;
}

const E* next() {
const E* next() const {
if (_p == NULL) return NULL;
const E* e = _p->peek();
_p = _p->next();
Expand Down
80 changes: 78 additions & 2 deletions 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
Expand Down Expand Up @@ -58,7 +58,7 @@ static void check_list_values(const int* expected, const LinkedList<Integer>* 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) {
Expand All @@ -85,6 +85,82 @@ TEST(LinkedList, simple) {
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;
Expand Down

0 comments on commit b08595d

Please sign in to comment.