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

net.automatalib.common.smartcollection.UnorderedCollection 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.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;

import org.checkerframework.checker.initialization.qual.UnknownInitialization;

/**
 * This class implements a collection for storing objects in no particular order.
 * 

* It supports (amortized) constant time insertion and removal. Removal does not invalidate the references of other * objects, and can be performed during iteration (using the respective {@link Iterator#remove()} method). * * @param * element class. */ public final class UnorderedCollection extends AbstractSmartCollection implements CapacityManagement { private static final int DEFAULT_INITIAL_CAPACITY = 10; // The collection's storage private final ResizingArrayStorage> storage; private int size; /** * Default constructor. Reserves capacity for 10 elements. */ public UnorderedCollection() { this(DEFAULT_INITIAL_CAPACITY); } /** * Constructor. Reserves the specified initial capacity. * * @param initialCapacity * the number of elements to reserve capacity for. */ public UnorderedCollection(int initialCapacity) { final int capacity = initialCapacity <= 0 ? DEFAULT_INITIAL_CAPACITY : initialCapacity; this.storage = new ResizingArrayStorage<>(Reference.class, capacity); } /** * Constructor. Initializes the collection with the contents of the specified collection. * * @param coll * the collection. */ public UnorderedCollection(Collection coll) { this(coll.size()); addAll(coll); } @Override public boolean ensureCapacity(@UnknownInitialization(UnorderedCollection.class) UnorderedCollection this, int minCapacity) { return storage.ensureCapacity(minCapacity); } @Override public boolean ensureAdditionalCapacity(int additionalSpace) { return ensureCapacity(size + additionalSpace); } @Override public void hintNextCapacity(int nextCapacityHint) { storage.hintNextCapacity(nextCapacityHint); } @Override public E get(ElementReference ref) { return UnorderedCollection.asIndexedRef(ref).element; } /** * Convenience method, renders a plain cast obsolete and throws a more specific exception if the cast fails. */ @SuppressWarnings("unchecked") private static Reference asIndexedRef(ElementReference ref) { if (ref.getClass() != Reference.class) { throw new InvalidReferenceException( "Reference is of wrong class '" + ref.getClass().getName() + "', should be " + Reference.class.getName() + "."); } return (Reference) ref; } @Override public ElementReference referencedAdd(E elem) { ensureCapacity(size + 1); int insertPos = size++; Reference ref = new Reference<>(elem, insertPos); storage.array[insertPos] = ref; return ref; } @Override public void remove(ElementReference ref) { remove(extractValidIndex(ref)); } /** * Removes an element by its index. */ @SuppressWarnings("nullness") // setting 'null' is fine, because we also decrease the size private void remove(int index) { int lastIndex = --size; Reference removed = storage.array[index]; Reference lastElem = storage.array[lastIndex]; storage.array[index] = lastElem; lastElem.index = index; removed.index = -1; storage.array[lastIndex] = null; } @Override public Iterator referenceIterator() { return new ReferenceIterator(); } @Override public void replace(ElementReference ref, E newElement) { int idx = extractValidIndex(ref); storage.array[idx].element = newElement; } /** * Convenience method for extracting the index stored in an ElementReference, and throws a more specific exception * if the cast fails or the index is not valid. */ private int extractValidIndex(ElementReference ref) { Reference iRef = asIndexedRef(ref); int idx = iRef.index; if (idx < 0 || idx >= size) { throw new InvalidReferenceException( "Index " + idx + " is not valid for collection with size " + size + "."); } return idx; } @Override public E choose() { if (size == 0) { throw new NoSuchElementException(); } return storage.array[0].element; } @Override public ElementReference chooseRef() { if (size == 0) { throw new NoSuchElementException(); } return storage.array[0]; } @Override public Iterable references() { return this::referenceIterator; } @Override public void addAll(T[] array) { ensureCapacity(size + array.length); for (T t : array) { storage.array[size] = new Reference<>(t, size); size++; } } @Override public boolean addAll(@UnknownInitialization(UnorderedCollection.class) UnorderedCollection this, Collection coll) { if (coll.isEmpty()) { return false; } ensureCapacity(size + coll.size()); for (E elem : coll) { storage.array[size] = new Reference<>(elem, size); size++; } return true; } @Override public void quickClear() { size = 0; } @SuppressWarnings("nullness") // setting 'null' is fine, when (according to JavaDoc) calling quickClear() first @Override public void deepClear() { storage.setAll(null); } @Override public Iterator iterator() { return new ElementIterator(); } @Override public int size() { return size; } @Override public boolean isEmpty() { return size == 0; } @SuppressWarnings("nullness") // setting 'null' is fine, because we also decrease the size @Override public void clear() { for (int i = 0; i < size; i++) { storage.array[i].index = -1; storage.array[i] = null; } size = 0; } /** * Swaps the contents of this {@link UnorderedCollection} with another one storing the same elements. This operation * runs in constant time, by only swapping storage references. * * @param other * the {@link UnorderedCollection} to swap contents with. */ public void swap(UnorderedCollection other) { int sizeTmp = size; size = other.size; other.size = sizeTmp; storage.swap(other.storage); } /** * The reference for this collection, effectively containing an index in addition to the element itself. */ private static class Reference implements ElementReference { public E element; public int index; /** * Constructor. * * @param element * the stored element. * @param index * its index. */ Reference(E element, int index) { this.element = element; this.index = index; } } /** * The iterator for iterating over the element references. */ private class ReferenceIterator implements Iterator { private int index; @Override public boolean hasNext() { return index < size; } @Override public ElementReference next() { if (index >= size) { throw new NoSuchElementException(); } return storage.array[index++]; } @Override public void remove() { UnorderedCollection.this.remove(--index); } } /** * The iterator for iterating over the elements themselves. */ private class ElementIterator implements Iterator { private int index; @Override public boolean hasNext() { return index < size; } @Override public E next() { if (index >= size) { throw new NoSuchElementException(); } return storage.array[index++].element; } @Override public void remove() { if (index <= 0) { throw new IllegalStateException(); } UnorderedCollection.this.remove(--index); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy