/* * 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 * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. *
*/
/* * The implementation of a generic linked list, which uses various * backing storages, such as C heap, arena and resource, etc.
*/
// An entry in a linked list. It should use the same backing storage // as the linked list that contains this entry. template <class E> class LinkedListNode : public AnyObj { private:
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> staticbool equal(const U& a, const U& b, bool (U::*t)(const U&) const) { return a.equals(b);
}
template <class U> staticbool equal(const U& a, const U& b, ...) { return a == b;
}
// A linked list interface. It does not specify // any storage type it uses, so all methods involving // memory allocation or deallocation are pure virtual template <class E> class LinkedList : public AnyObj { protected:
LinkedListNode<E>* _head;
NONCOPYABLE(LinkedList<E>);
inline size_t size() const {
LinkedListNode<E>* p;
size_t count = 0; for (p = head(); p != NULL; count++, p = p->next()); return count;
}
// Move all entries from specified linked list to this one virtualvoid move(LinkedList<E>* list) = 0;
// Add an entry to this linked list virtual LinkedListNode<E>* add(const E& e) = 0; // Add all entries from specified linked list to this one, virtualvoid add(LinkedListNode<E>* node) = 0;
// Add a linked list to this linked list virtualbool add(const LinkedList<E>* list) = 0;
// Search entry in the linked list virtual LinkedListNode<E>* find_node(const E& e) = 0; virtual E* find(const E& e) = 0;
// Insert entry to the linked list virtual LinkedListNode<E>* insert_before(const E& e, LinkedListNode<E>* ref) = 0; virtual LinkedListNode<E>* insert_after (const E& e, LinkedListNode<E>* ref) = 0;
// Remove entry from the linked list virtualbool remove(const E& e) = 0; virtualbool remove(LinkedListNode<E>* node) = 0; virtualbool remove_before(LinkedListNode<E>* ref) = 0; virtualbool remove_after(LinkedListNode<E>* ref) = 0;
LinkedListNode<E>* unlink_head() {
LinkedListNode<E>* h = this->head(); if (h != NULL) {
this->set_head(h->next());
} return h;
}
// A linked list implementation. // The linked list can be allocated in various type of memory: C heap, arena and resource area, etc. template <class E, AnyObj::allocation_type T = AnyObj::C_HEAP,
MEMFLAGS F = mtNMT, AllocFailType alloc_failmode = AllocFailStrategy::RETURN_NULL> class LinkedListImpl : public LinkedList<E> { protected:
Arena* _arena; public:
LinkedListImpl() : _arena(NULL) { }
LinkedListImpl(Arena* a) : _arena(a) { }
virtual ~LinkedListImpl() {
clear();
}
virtualvoid clear() {
LinkedListNode<E>* p = this->head();
this->set_head(NULL); while (p != NULL) {
LinkedListNode<E>* to_delete = p;
p = p->next();
delete_node(to_delete);
}
}
// Add an entry to the linked list virtual LinkedListNode<E>* add(const E& e) {
LinkedListNode<E>* node = this->new_node(e); if (node != NULL) {
this->add(node);
}
// Move a linked list to this linked list, both have to be allocated on the same // storage type. virtualvoid move(LinkedList<E>* list) {
assert(list->storage_type() == this->storage_type(), "Different storage type");
LinkedListNode<E>* node = this->head(); while (node != NULL && node->next() != NULL) {
node = node->next();
} if (node == NULL) {
this->set_head(list->head());
} else {
node->set_next(list->head());
} // All entries are moved
list->set_head(NULL);
}
// Add an entry in front of the reference entry
LinkedListNode<E>* insert_before(const E& e, LinkedListNode<E>* ref_node) {
LinkedListNode<E>* node = this->new_node(e); if (node == NULL) return NULL; if (ref_node == this->head()) {
node->set_next(ref_node);
this->set_head(node);
} else {
LinkedListNode<E>* p = this->head(); while (p != NULL && p->next() != ref_node) {
p = p->next();
}
assert(p != NULL, "ref_node not in the list");
node->set_next(ref_node);
p->set_next(node);
} return node;
}
// Add an entry behind the reference entry
LinkedListNode<E>* insert_after(const E& e, LinkedListNode<E>* ref_node) {
LinkedListNode<E>* node = this->new_node(e); if (node == NULL) return NULL;
node->set_next(ref_node->next());
ref_node->set_next(node); return node;
}
// Remove an entry from the linked list. // Return true if the entry is successfully removed virtualbool remove(const E& e) {
LinkedListNode<E>* tmp = this->head();
LinkedListNode<E>* prev = NULL;
while (tmp != NULL) { if (tmp->equals(e)) { return remove_after(prev);
}
prev = tmp;
tmp = tmp->next();
} returnfalse;
}
// Remove the node after the reference entry virtualbool remove_after(LinkedListNode<E>* prev) {
LinkedListNode<E>* to_delete; if (prev == NULL) {
to_delete = this->unlink_head();
} else {
to_delete = prev->next(); if (to_delete != NULL) {
prev->set_next(to_delete->next());
}
}
if (to_delete != NULL) {
delete_node(to_delete); returntrue;
} returnfalse;
}
virtualbool remove(LinkedListNode<E>* node) {
LinkedListNode<E>* p = this->head(); if (p == node) {
this->set_head(p->next());
delete_node(node); returntrue;
} while (p != NULL && p->next() != node) {
p = p->next();
} if (p != NULL) {
p->set_next(node->next());
delete_node(node); returntrue;
} else { returnfalse;
}
}
virtualbool remove_before(LinkedListNode<E>* ref) {
assert(ref != NULL, "NULL pointer");
LinkedListNode<E>* p = this->head();
LinkedListNode<E>* to_delete = NULL; // to be deleted
LinkedListNode<E>* prev = NULL; // node before the node to be deleted while (p != NULL && p != ref) {
prev = to_delete;
to_delete = p;
p = p->next();
} if (p == NULL || to_delete == NULL) returnfalse;
assert(to_delete->next() == ref, "Wrong node to delete");
assert(prev == NULL || prev->next() == to_delete, "Sanity check"); if (prev == NULL) {
assert(to_delete == this->head(), "Must be head");
this->set_head(to_delete->next());
} else {
prev->set_next(to_delete->next());
}
delete_node(to_delete); returntrue;
}
DEBUG_ONLY(AnyObj::allocation_type storage_type() { return T; }) protected: // Create new linked list node object in specified storage
LinkedListNode<E>* new_node(const E& e) const { switch(T) { case AnyObj::ARENA: {
assert(_arena != NULL, "Arena not set"); returnnew(_arena) LinkedListNode<E>(e);
} case AnyObj::RESOURCE_AREA: if (alloc_failmode == AllocFailStrategy::RETURN_NULL) { returnnew(std::nothrow) LinkedListNode<E>(e);
} else { returnnew LinkedListNode<E>(e);
} case AnyObj::C_HEAP: { if (alloc_failmode == AllocFailStrategy::RETURN_NULL) { returnnew(std::nothrow, F) LinkedListNode<E>(e);
} else { returnnew(F) LinkedListNode<E>(e);
}
} default:
ShouldNotReachHere();
} return NULL;
}
// Delete linked list node object void delete_node(LinkedListNode<E>* node) { if (T == AnyObj::C_HEAP) { delete node;
}
}
};
// Sorted linked list. The linked list maintains sorting order specified by the comparison // function template <class E, int (*FUNC)(const E&, const E&),
AnyObj::allocation_type T = AnyObj::C_HEAP,
MEMFLAGS F = mtNMT, AllocFailType alloc_failmode = AllocFailStrategy::RETURN_NULL> class SortedLinkedList : public LinkedListImpl<E, T, F, alloc_failmode> { public:
SortedLinkedList() { }
SortedLinkedList(Arena* a) : LinkedListImpl<E, T, F, alloc_failmode>(a) { }
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.