All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.automatalib.common.smartcollection.AbstractLinkedList Maven / Gradle / Ivy

Go to download

This library provides efficient implementations for various collection data structures (esp. linked lists and priority queues), which have very insufficient implementation in the Java Collections Foundations that makes it hard or even impossible to exploit their efficiencies.

The newest version!
/* Copyright (C) 2013-2023 TU Dortmund
 * This file is part of AutomataLib, http://www.automatalib.net/.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.automatalib.common.smartcollection;

import java.util.Iterator;
import java.util.NoSuchElementException;

import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.framework.qual.EnsuresQualifierIf;

/**
 * Abstract base class for linked lists.
 * 

* This class implements the base functionality for dealing with linked lists of elements implementing the {@link * LinkedListEntry} interface. It provides the logic for the basic operations (esp. the (re-/un-)linking of elements), * but not how entries into the lists are created. Therefore, it can be used by both intrusive and non-intrusive linked * lists. * * @param * element type * @param * linked list entry type * * @see IntrusiveLinkedList * @see DefaultLinkedList */ public abstract class AbstractLinkedList> extends AbstractSmartCollection implements SmartSequence { // head element (may be null if list is empty) private @Nullable T head; // last element (may be null if list is empty) private @Nullable T last; // number of elements in the list private int size; /** * Retrieves the first entry in the list, or null if the list is empty. * * @return the first entry or null. */ protected @Nullable T getFrontEntry() { return head; } /** * Retrieves the last entry in the list, or null if the list is empty. * * @return the first entry or null. */ protected @Nullable T getBackEntry() { return last; } /** * Concatenates two linked lists. All elements of the specified list (which will be empty afterward) are added at * the end of this list. This operation runs in constant time. * * @param other * the list to append, */ public void concat(AbstractLinkedList other) { if (other.isEmpty()) { return; } if (isEmpty()) { head = other.head; } else { T otherHead = other.head; last.setNext(otherHead); otherHead.setPrev(last); } last = other.last; size += other.size; other.clear(); } @Override public E choose() { if (head == null) { throw new NoSuchElementException(); } return head.getElement(); } @Override public ElementReference chooseRef() { if (head == null) { throw new NoSuchElementException(); } return head; } @Override public Iterator iterator() { return new ElementIterator(head); } @Override @SuppressWarnings("unchecked") public E get(ElementReference ref) { return ((T) ref).getElement(); } @Override public ElementReference referencedAdd(E elem) { T entry = makeEntry(elem); pushBackEntry(entry); return entry; } @Override @SuppressWarnings("unchecked") public void remove(ElementReference elem) { removeEntry((T) elem); } /** * Removes an entry from the list. * * @param entry * the entry to remove. */ protected void removeEntry(T entry) { T prev = entry.getPrev(); T next = entry.getNext(); if (prev != null) { prev.setNext(next); } else { head = next; } if (next != null) { next.setPrev(prev); } else { last = prev; } size--; } @Override @SuppressWarnings("unchecked") public Iterator referenceIterator() { return (Iterator) (Iterator) new LinkedListEntryIterator(head); } @Override @SuppressWarnings("unchecked") public void replace(ElementReference ref, E newElement) { T newEntry = makeEntry(newElement); replaceEntry((T) ref, newEntry); } /** * Replaces an entry in the list. * * @param oldEntry * the entry to be replaced. * @param newEntry * the replacement entry. */ protected void replaceEntry(T oldEntry, T newEntry) { T prev = oldEntry.getPrev(); T next = newEntry.getNext(); if (prev != null) { prev.setNext(newEntry); } else { head = newEntry; } if (next != null) { next.setPrev(newEntry); } else { last = newEntry; } } /** * Creates (if necessary) a {@link LinkedListEntry} for the given element. For intrusive linked lists, e.g., the * argument itself is returned. * * @param element * the element for which to retrieve an entry. * * @return the entry for the given element. */ protected abstract T makeEntry(E element); /** * Adds an entry at the end of the list. * * @param e * the entry to add. */ protected void pushBackEntry(T e) { e.setNext(null); e.setPrev(last); if (last != null) { last.setNext(e); } else { head = e; } last = e; size++; } @Override public int size() { return size; } @Override @EnsuresQualifierIf(qualifier = NonNull.class, expression = {"this.head", "this.last"}, result = false) public boolean isEmpty() { return head == null || last == null; } @Override public void clear() { head = null; last = null; size = 0; } /** * Retrieves the last element in the list. If the list is empty, a {@link NoSuchElementException} will be thrown. * * @return the last element in the list. */ public E getBack() { if (last == null) { throw new NoSuchElementException(); } return last.getElement(); } /** * Retrieves a reference to the last element in the list. If the list is empty, null is returned. * * @return a reference to the last element, or null. */ public @Nullable ElementReference getBackReference() { return last; } /** * Retrieves the first element in the list. If the list is empty, a {@link NoSuchElementException} will be thrown * * @return the first element in the list. */ public E getFront() { if (head == null) { throw new NoSuchElementException(); } return head.getElement(); } /** * Retrieves a reference to the first element in the list. If the list is empty, null is returned. * * @return a reference to the first element, or null. */ public @Nullable ElementReference getFrontReference() { return head; } /** * Retrieves and removes the last element in the list. If the list is empty, a {@link NullPointerException} may be * thrown. * * @return the formerly last element in the list. */ @SuppressWarnings("nullness") // fine according to JavaDoc public E popBack() { return popBackEntry().getElement(); } /** * Removes and returns the last entry in the list. If the list is empty, it remains unmodified and null * is returned. * * @return the previously first entry in the list, or null. */ @SuppressWarnings("nullness") // since intermediate method calls must not change the head reference, e is non-null protected @Nullable T popBackEntry() { if (last == null) { return null; } T prev = last.getPrev(); if (prev != null) { prev.setNext(null); } else { head = null; } T e = last; last = prev; e.setPrev(null); size--; return e; } /** * Retrieves and removes the first element in the list. If the list is empty, a {@link NullPointerException} may be * thrown. * * @return the formerly first element in the list. */ @SuppressWarnings("nullness") // fine according to JavaDoc public E popFront() { return popFrontEntry().getElement(); } /** * Removes and returns the first entry in the list. If the list is empty, it remains unmodified and * null is returned. * * @return the previously first entry in the list, or null. */ @SuppressWarnings("nullness") // since intermediate method calls must not change the head reference, e is non-null protected @Nullable T popFrontEntry() { if (head == null) { return null; } T next = head.getNext(); if (next != null) { next.setPrev(null); } else { last = null; } T e = head; head = next; e.setNext(null); size--; return e; } /** * Adds an element at the end of the list. * * @param element * the element to add. * * @return a reference to the newly added element. */ public ElementReference pushBack(E element) { T entry = makeEntry(element); pushBackEntry(entry); return entry; } /** * Adds an element at the beginning of the list. * * @param element * the element to add. * * @return a reference to the newly added element. */ public ElementReference pushFront(E element) { T entry = makeEntry(element); pushFrontEntry(entry); return entry; } /** * Adds an entry at the beginning of the list. * * @param e * the entry to add. */ protected void pushFrontEntry(T e) { e.setPrev(null); e.setNext(head); if (head != null) { head.setPrev(e); } else { last = e; } head = e; size++; } @Override public @Nullable ElementReference pred(ElementReference ref) { return castRef(ref).getPrev(); } /** * Helper function for casting a general {@link ElementReference} to the specific linked list entry type. * * @param ref * the reference. * * @return the argument cast to the entry type. */ @SuppressWarnings("unchecked") protected T castRef(ElementReference ref) { return (T) ref; } @Override public @Nullable ElementReference succ(ElementReference ref) { return castRef(ref).getNext(); } @Override @SuppressWarnings("unchecked") public ElementReference insertBefore(E element, ElementReference ref) { T entry = makeEntry(element); insertBeforeEntry(entry, (T) ref); return entry; } /** * Inserts a new entry before a given one. * * @param e * the entry to add. * @param insertPos * the entry before which to add the new one. */ protected void insertBeforeEntry(T e, T insertPos) { T oldPrev = insertPos.getPrev(); e.setNext(insertPos); e.setPrev(oldPrev); insertPos.setPrev(e); if (oldPrev != null) { oldPrev.setNext(e); } else { head = e; } size++; } @Override @SuppressWarnings("unchecked") public ElementReference insertAfter(E element, ElementReference ref) { T entry = makeEntry(element); insertAfterEntry(entry, (T) ref); return entry; } /** * Inserts a new entry after a given one. * * @param e * the entry to add. * @param insertPos * the entry before which to add the new one. */ protected void insertAfterEntry(T e, T insertPos) { T oldNext = insertPos.getNext(); e.setNext(oldNext); e.setPrev(insertPos); insertPos.setNext(e); if (oldNext != null) { oldNext.setPrev(e); } else { last = e; } size++; } /** * Swaps the contents of two linked lists with the same entry types. This method runs in constant time. * * @param other * the other list to swap contents with. */ public void swap(AbstractLinkedList other) { int sizeTmp = this.size; T headTmp = this.head; T lastTmp = this.last; this.size = other.size; this.head = other.head; this.last = other.last; other.size = sizeTmp; other.head = headTmp; other.last = lastTmp; } /** * Iterator that follows the linked structure of the elements. */ private class LinkedListEntryIterator implements Iterator { // previous entry private @Nullable T prev; // current entry private @Nullable T current; /* * Constructor. */ LinkedListEntryIterator(@Nullable T head) { this.current = head; } @Override public boolean hasNext() { return current != null; } @Override public T next() { if (current == null) { throw new NoSuchElementException(); } T e = current; current = current.getNext(); prev = e; return e; } @Override public void remove() { if (prev == null) { throw new IllegalStateException(); } removeEntry(prev); prev = null; } } private class ElementIterator implements Iterator { // previous entry private @Nullable T prev; // current entry private @Nullable T current; /* * Constructor. */ ElementIterator(@Nullable T head) { this.current = head; } @Override public boolean hasNext() { return current != null; } @Override public E next() { if (current == null) { throw new NoSuchElementException(); } T e = current; current = current.getNext(); prev = e; return e.getElement(); } @Override public void remove() { if (prev == null) { throw new IllegalStateException(); } removeEntry(prev); prev = null; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy