AbstractHistoricalCollection.java
package org.opentrafficsim.core.perception.collections;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import org.djunits.value.vdouble.scalar.Time;
import org.opentrafficsim.core.perception.AbstractHistorical;
import org.opentrafficsim.core.perception.HistoryManager;
import org.opentrafficsim.core.perception.collections.AbstractHistoricalCollection.EventCollection;
/**
* Collection-valued historical state. The current collection is always maintained, and past states of the collection are
* obtained by applying the events between now and the requested time in reverse.<br>
* <br>
* This implementation is suitable for sets, as add and remove events to retrieve historical states are only created if indeed
* the underlying collection is changed. {@code Set} introduces no new methods relative to {@code Collection}.<br>
* <br>
* The {@code Iterator} returned by this class does not support the {@code remove()} method.
* <p>
* Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
* BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
* </p>
* @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
* @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
* @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
* @param <E> element type
* @param <C> collection type
*/
public abstract class AbstractHistoricalCollection<E, C extends Collection<E>>
extends AbstractHistorical<E, EventCollection<E, C>> implements HistoricalCollection<E>
{
/** Current collection. */
private final C current;
/**
* Constructor.
* @param historyManager HistoryManager; history manager
* @param collection C; initial collection
*/
protected AbstractHistoricalCollection(final HistoryManager historyManager, final C collection)
{
super(historyManager);
this.current = collection;
}
/**
* Returns the internal collection.
* @return C; internal collection
*/
protected final C getCollection()
{
return this.current;
}
/**
* Fill collection with the current collection.
* @param collection C; collection to fill
* @return C; input collection filled
*/
protected final C fill(final C collection)
{
collection.addAll(this.current);
return collection;
}
/**
* Fill collection with the collection at the given simulation time.
* @param time Time; time
* @param collection C; collection to fill
* @return C; input collection filled
*/
protected final C fill(final Time time, final C collection)
{
// copy all current elements and decrement per event
collection.addAll(this.current);
for (EventCollection<E, C> event : getEvents(time))
{
event.restore(collection);
}
return collection;
}
// Altering Collection methods
/** {@inheritDoc} */
@Override
public boolean add(final E value)
{
boolean added = getCollection().add(value);
if (added)
{
addEvent(new AddEvent<>(now().si, value));
}
return added;
}
/** {@inheritDoc} */
@Override
public boolean addAll(final Collection<? extends E> c)
{
boolean changed = false;
for (E value : c)
{
changed |= add(value);
}
return changed;
}
/** {@inheritDoc} */
@Override
public void clear()
{
new LinkedHashSet<>(this.current).forEach(this::remove);
}
/** {@inheritDoc} */
@Override
@SuppressWarnings("unchecked")
public boolean remove(final Object value)
{
boolean removed = getCollection().remove(value);
if (removed)
{
addEvent(new RemoveEvent<>(now().si, (E) value)); // contains, so safe cast
}
return removed;
}
/** {@inheritDoc} */
@Override
public boolean removeAll(final Collection<?> c)
{
boolean changed = false;
for (Object value : c)
{
changed |= remove(value);
}
return changed;
}
/** {@inheritDoc} */
@Override
public boolean retainAll(final Collection<?> c)
{
boolean changed = false;
Set<E> values = new LinkedHashSet<>(this.current);
for (E value : values)
{
if (!c.contains(value))
{
changed |= remove(value);
}
}
return changed;
}
// Non-altering Collection methods
/** {@inheritDoc} */
@Override
public int size()
{
return this.current.size();
}
/** {@inheritDoc} */
@Override
public boolean isEmpty()
{
return this.current.isEmpty();
}
/** {@inheritDoc} */
@Override
public boolean contains(final Object o)
{
return this.current.contains(o);
}
/** {@inheritDoc} */
@Override
public Iterator<E> iterator()
{
return Collections.unmodifiableCollection(this.current).iterator();
}
/** {@inheritDoc} */
@Override
public Object[] toArray()
{
return this.current.toArray();
}
/** {@inheritDoc} */
@Override
public <T> T[] toArray(final T[] a)
{
return this.current.toArray(a);
}
/** {@inheritDoc} */
@Override
public boolean containsAll(final Collection<?> c)
{
return this.current.containsAll(c);
}
// Events
/**
* Abstract super class for events that add or remove a value from the collection.
* <p>
* Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
* <br>
* BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
* </p>
* @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
* @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
* @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
* @param <E> element type
* @param <C> collection type
*/
public abstract static class EventCollection<E, C extends Collection<E>> extends AbstractHistorical.EventValue<E>
{
/**
* Constructor.
* @param time double; time of event
* @param value E; value of event
*/
public EventCollection(final double time, final E value)
{
super(time, value);
}
/**
* Restores the collection to the state of before the event.
* @param collection C; collection to restore
*/
public abstract void restore(C collection);
/** {@inheritDoc} */
@Override
public String toString()
{
return "EventCollection []";
}
}
/**
* Event for adding value to the collection.
* <p>
* Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
* <br>
* BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
* </p>
* @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
* @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
* @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
* @param <E> element type
* @param <C> collection type
*/
public static class AddEvent<E, C extends Collection<E>> extends EventCollection<E, C>
{
/**
* Constructor.
* @param time double; time of event
* @param value E; value of event
*/
public AddEvent(final double time, final E value)
{
super(time, value);
}
/** {@inheritDoc} */
@Override
public void restore(final C collection)
{
collection.remove(getValue()); // events are only created upon effective addition, so we can remove it
}
/** {@inheritDoc} */
@Override
public String toString()
{
return "AddEvent []";
}
}
/**
* Event for removing value from the collection.
* <p>
* Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
* <br>
* BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
* </p>
* @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
* @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
* @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
* @param <E> element type
* @param <C> collection type
*/
public static class RemoveEvent<E, C extends Collection<E>> extends EventCollection<E, C>
{
/**
* Constructor.
* @param time double; time of event
* @param value E; value of event
*/
public RemoveEvent(final double time, final E value)
{
super(time, value);
}
/** {@inheritDoc} */
@Override
public void restore(final C collection)
{
collection.add(getValue()); // events are only created upon effective removal, so we can add it
}
/** {@inheritDoc} */
@Override
public String toString()
{
return "RemoveEvent []";
}
}
}