
monniasza.collects.alloc.SimpleAllocator Maven / Gradle / Ivy
/**
*
*/
package monniasza.collects.alloc;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.Consumer;
import com.google.common.collect.Iterators;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntIterator;
import it.unimi.dsi.fastutil.ints.IntList;
/**
* @author oskar
* @param
* An implementation of the allocator.
* Exceptions thrown by listeners are forwarded to the {@code exceptionHandler} object in this allocator
* The {@code exceptionHandler} by default forwards exceptions to the thread's current UncaughtExceptionHandler, where thread is the thread used to run listeners
*/
public class SimpleAllocator implements Allocator {
private Consumer exceptionHandler = (ex -> {
UncaughtExceptionHandler ueh = Thread.currentThread().getUncaughtExceptionHandler();
if(ueh != null) ueh.uncaughtException(Thread.currentThread(), ex);
});
private ArrayList data = new ArrayList<>();
private IntList free = new IntArrayList();
private class Node{
Node(T value) {
super();
this.value = value;
}
T value() {
return value;
}
final T value;
List> nodeListeners = new ArrayList<>();
}
@Override
public int allocate(T obj) {
Node node = new Node(obj);
int next;
if(free.isEmpty()) {
//Generate new values
next = data.size();
data.add(node);
}else {
//Reuse the value
IntIterator iterator = free.intIterator();
next = iterator.nextInt();
iterator.remove();
data.set(next, node);
}
for(AllocationListener listener: listeners) {
try {
listener.allocated(next, obj);
}catch(Exception e) {
exceptionHandler.accept(e);
}
}
return next;
}
@Override
public void destroy(int id) {
if(!isAllocated(id)) throw new NoSuchElementException("Index "+id+" does not exist");
Node result = data.get(id);
T value = null;
if(result != null) value = result.value;
for(AllocationListener listener: listeners) {
try {
listener.deallocated(id, value);
}catch(Exception e) {
exceptionHandler.accept(e);
}
}
if(result != null) for(AllocationListener listener: result.nodeListeners) {
try {
listener.deallocated(id, value);
}catch(Exception e) {
exceptionHandler.accept(e);
}
}
free.add(id);
data.set(id, null);
}
private List> listeners = new ArrayList<>();
@Override
public void addAllocationListener(AllocationListener listener) {
listeners.add(listener);
}
@Override
public void removeAllocationListener(AllocationListener listener) {
listeners.remove(listener);
}
@Override
public void addSpecificAllocationListener(AllocationListener listener, int index) {
Node result = data.get(index);
if(result != null) result.nodeListeners.add(listener);
}
@Override
public void removeSpecificAllocationListener(AllocationListener listener, int index) {
Node result = data.get(index);
if(result != null) result.nodeListeners.remove(listener);
}
/**
* @return current exception handler
*/
public Consumer getExceptionHandler() {
return exceptionHandler;
}
/**
* @param exceptionHandler new exception handler
*/
public void setExceptionHandler(Consumer exceptionHandler) {
this.exceptionHandler = exceptionHandler;
}
@Override
public boolean isAllocated(int id) {
if(id >= data.size()) return false;
return data.get(id) != null;
}
@Override
public T get(int id) {
Node result = data.get(id);
if(result == null) return null;
return result.value;
}
@Override
public int size() {
return data.size();
}
@SuppressWarnings("null")
@Override
public Iterator iterator() {
return Iterators.transform(Iterators.filter(data.iterator(), Objects::nonNull), Node::value);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy