DoubleAppendList.java
package nl.tudelft.simulation.dsol.animation.graph;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* DoubleList is a random access list of double values to which values can only be appended. It stores the values as primitives
* rather than as wrapping Objects. For the rest, it behaves like a regular list, with the exception of the absence of the
* add(i, value) method and the remove methods.
* <p>
* Copyright (c) 2020-2024 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
* for project information <a href="https://simulation.tudelft.nl/dsol/manual/" target="_blank">DSOL Manual</a>. The DSOL
* project is distributed under a three-clause BSD-style license, which can be found at
* <a href="https://https://simulation.tudelft.nl/dsol/docs/latest/license.html" target="_blank">DSOL License</a>.
* </p>
* @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
*/
public class DoubleAppendList implements Iterable<Double>, Serializable
{
/** */
private static final long serialVersionUID = 20210103L;
/** the chunk size. */
private static final int CHUNK_SIZE = 256;
/** the number of bits of the chunk size. */
private static final int CHUNK_BITS = 8;
/** the mask for the rightmost CHUNK_BITS bits. */
private static final int CHUNK_MASK = CHUNK_SIZE - 1;
/** the backing list with chunks. */
private final List<double[]> storage = new ArrayList<>();
/** the current chunk, already stored in the List. */
private double[] currentChunk;
/** the total number of elements. */
private int numElements;
/** the current in-chunk counter that indicates the next value to be written. */
private int inChunkNext;
/**
* Initialize the DoubleAppendList.
*/
public DoubleAppendList()
{
this.numElements = 0;
this.inChunkNext = 0;
this.currentChunk = new double[CHUNK_SIZE];
this.storage.add(this.currentChunk);
}
/**
* Add a value to the list.
* @param value double; the value to add
*/
public void add(final double value)
{
if (this.inChunkNext == CHUNK_SIZE)
{
this.inChunkNext = 0;
this.currentChunk = new double[CHUNK_SIZE];
this.storage.add(this.currentChunk);
}
this.currentChunk[this.inChunkNext] = value;
this.inChunkNext++;
this.numElements++;
}
/**
* Return the number of elements.
* @return int; the number of elements
*/
public int size()
{
return this.numElements;
}
/**
* Return the value at a position.
* @param i int; the position
* @return double; the value at the position
* @throws IndexOutOfBoundsException when i < 0 or i > number of values
*/
public double get(final int i)
{
if (i < 0 || i >= this.numElements)
{
throw new IndexOutOfBoundsException("DoubleAppendList.get(i) -- i out of bounds.");
}
return this.storage.get(i >> CHUNK_BITS)[i & CHUNK_MASK];
}
/** {@inheritDoc} */
@Override
public Iterator<Double> iterator()
{
return new DoubleAppendIterator(this);
}
/**
* An iterator for the DoubleAppendList.
*/
class DoubleAppendIterator implements Iterator<Double>
{
/** the list to iterate over. */
private final DoubleAppendList list;
/** the counter. */
private int counter;
/**
* Make an iterator for the DoubleAppendList.
* @param list DoubleAppendList; the list to iterate over
*/
DoubleAppendIterator(final DoubleAppendList list)
{
this.list = list;
this.counter = 0;
}
/** {@inheritDoc} */
@Override
public boolean hasNext()
{
return this.counter < this.list.size();
}
/** {@inheritDoc} */
@Override
public Double next()
{
return this.list.get(this.counter++);
}
}
}