Add support for node predicate, fast exit when the node type is incompatible

This commit is contained in:
TheMode 2021-08-19 22:21:51 +02:00
parent 43fc7ad624
commit 044849b5ac

View File

@ -14,11 +14,10 @@ import java.util.function.Consumer;
class EventNodeImpl<T extends Event> implements EventNode<T> { class EventNodeImpl<T extends Event> implements EventNode<T> {
private static final Object GLOBAL_CHILD_LOCK = new Object(); private static final Object GLOBAL_CHILD_LOCK = new Object();
private final Object lock = new Object();
private final Map<Class<? extends T>, Handle<T>> handleMap = new ConcurrentHashMap<>(); private final Map<Class<? extends T>, Handle<T>> handleMap = new ConcurrentHashMap<>();
private final Map<Class<? extends T>, ListenerEntry<T>> listenerMap = new ConcurrentHashMap<>(); private final Map<Class<? extends T>, ListenerEntry<T>> listenerMap = new ConcurrentHashMap<>();
private final Set<EventNode<T>> children = new CopyOnWriteArraySet<>(); private final Set<EventNodeImpl<T>> children = new CopyOnWriteArraySet<>();
private final Map<Object, ListenerEntry<T>> mappedNodeCache = new WeakHashMap<>(); private final Map<Object, ListenerEntry<T>> mappedNodeCache = new WeakHashMap<>();
private final String name; private final String name;
@ -45,7 +44,7 @@ class EventNodeImpl<T extends Event> implements EventNode<T> {
if (!castedHandle.updated) { if (!castedHandle.updated) {
listeners.clear(); listeners.clear();
synchronized (GLOBAL_CHILD_LOCK) { synchronized (GLOBAL_CHILD_LOCK) {
handle(castedHandle); handle(castedHandle.eventType, castedHandle.listeners);
} }
castedHandle.updated = true; castedHandle.updated = true;
} }
@ -61,22 +60,33 @@ class EventNodeImpl<T extends Event> implements EventNode<T> {
aClass -> new Handle<>(this, (Class<T>) aClass)); aClass -> new Handle<>(this, (Class<T>) aClass));
} }
private void handle(Handle<T> handle) { private void handle(Class<T> handleType, List<Consumer<T>> listeners) {
ListenerEntry<T> entry = listenerMap.get(handle.eventType); ListenerEntry<T> entry = listenerMap.get(handleType);
if (entry != null) { if (entry != null) {
// Add normal listeners // Add normal listeners
for (var listener : entry.listeners) { for (var listener : entry.listeners) {
handle.listeners.add(listener::run); if (predicate != null) {
// Ensure that the event is valid before running
listeners.add(event -> {
final var value = filter.getHandler(event);
if (!predicate.test(event, value)) return;
listener.run(event);
});
} else {
// No predicate, run directly
listeners.add(listener::run);
}
} }
// Add bindings // Add bindings
handle.listeners.addAll(entry.bindingConsumers); listeners.addAll(entry.bindingConsumers);
// TODO mapped node // TODO mapped node
} }
// Add children // Add children
if (children.isEmpty()) return; if (children.isEmpty()) return;
this.children.stream() this.children.stream()
.sorted(Comparator.comparing(EventNode::getPriority)) .sorted(Comparator.comparing(EventNode::getPriority))
.forEach(child -> ((EventNodeImpl) child).handle(handle)); .filter(child -> child.eventType.isAssignableFrom(handleType)) // Invalid event type
.forEach(child -> child.handle(handleType, listeners));
} }
@Override @Override