blob: d5c0a6f992eab73d54e037a736d78aa7f5300eda [file] [log] [blame]
package org.eclipse.osee.ote.core;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReentrantLock;
/**
* This class is useful for cases where frequent looping and thread safety happen.
* It forces you to get a reference to the backing array and expects you to do a
* non Iterator based loop so that no Iterator objects are created to minimized GC churn.
*
* @author Andrew M Finkbeiner
*
* @param <E>
*/
public class CopyOnWriteNoIteratorList<E> {
private ReentrantLock lock = new ReentrantLock();
private AtomicReference<E[]> data = new AtomicReference<>();
private Class<E> type;
public CopyOnWriteNoIteratorList(Class<E> type){
this.type = type;
data.set(newArray(0));
}
@SuppressWarnings("unchecked")
private E[] newArray(int size){
return (E[]) Array.newInstance(type, size);
}
public void add(E item){
try{
lock.lock();
E[] ref = data.get();
E[] newdata = newArray(ref.length + 1);
System.arraycopy(ref, 0, newdata, 0, ref.length);
newdata[newdata.length-1] = item;
data.set(newdata);
} finally{
lock.unlock();
}
}
public boolean remove(E item){
boolean returnvalue = false;
try{
lock.lock();
int index = -1;
E[] ref = data.get();
for(int i = 0; i < ref.length; i++){
if(item.equals(ref[i])){
index = i;
break;
}
}
if(index > -1){
E[] newdata = newArray(ref.length - 1);
if(index == 0){
System.arraycopy(ref, 1, newdata, 0, newdata.length);
} else if (index == (ref.length - 1)){
System.arraycopy(ref, 0, newdata, 0, newdata.length);
} else {
System.arraycopy(ref, 0, newdata, 0, index);
System.arraycopy(ref, index+1, newdata, index, ref.length - (index + 1));
}
data.set(newdata);
returnvalue = true;
}
} finally {
lock.unlock();
}
return returnvalue;
}
public boolean contains(E item){
boolean returnValue = false;
try{
lock.lock();
int index = -1;
E[] ref = data.get();
for(int i = 0; i < ref.length; i++){
if(item.equals(ref[i])){
index = i;
break;
}
}
if(index > -1){
returnValue = true;
}
} finally {
lock.unlock();
}
return returnValue;
}
public E[] get(){
return data.get();
}
public int length() {
return data.get().length;
}
public void clear() {
try{
lock.lock();
data.set(newArray(0));
} finally{
lock.unlock();
}
}
public Collection<E> fillCollection(Collection<E> arrayList) {
try{
lock.lock();
E[] ref = data.get();
for(int i = 0; i < ref.length; i++){
arrayList.add(ref[i]);
}
} finally {
lock.unlock();
}
return arrayList;
}
}