package jaci.openrio.toast.lib.state;
import java.util.ArrayList;
import java.util.Iterator;
/**
* Why the extra Join and Remove Queues you ask? Well, if a module that is currently in a ticking or transition state wants
* to add or remove a listener from the list, we run into some errors. Without 'synchronized', we run into a Concurrent
* Modification, which causes big issues. With 'synchronized', the Thread will be forever blocked because it's trying to access
* a synchronized lock from INSIDE the synchronized method. I hate iteration iteration iteration iteration iteration iteration
* iteration iteration iteration iteration iteration iteration iteration....
*
* @author Jaci
*/
public class ConcurrentVector<E> extends ArrayList<E> {
ArrayList<E> joinQueue = new ArrayList<E>();
ArrayList<E> removeQueue = new ArrayList<E>();
boolean changed = false;
/**
* Push an element into the Concurrent Vector. This element will be added to the
* main vector/list when using the {@link #tick()} method
*/
public void addConcurrent(E element) {
joinQueue.add(element);
changed = true;
}
/**
* Pull and release an element from the Concurrent Vector. This element will be removed
* from the main vector/list when using the {@link #tick()} method
*/
public void removeConcurrent(E element) {
removeQueue.add(element);
changed = true;
}
/**
* Tick the vector. When called, this method will take all the recently added/removed objects and
* pass them into/out of the main list. This allows the Vector to be accessed by multiple objects when
* the list is being iterated over. Call this before calling .get() or other, similar methods.
*/
public void tick() {
if (!changed) return;
Iterator<E> joinIt = joinQueue.iterator();
while (joinIt.hasNext()) {
this.add(joinIt.next());
joinIt.remove();
}
Iterator<E> removeIt = removeQueue.iterator();
while (removeIt.hasNext()) {
this.remove(removeIt.next());
removeIt.remove();
}
changed = false;
removeIt = null;
joinIt = null;
}
}