I have made an event system, however, it is too slow.
The issue, is that there are multiple entries in a map that I never actually added. I don’t understand how they get there.
public class OrdinalMap<V> {
private final Map<Integer, V> map;
public OrdinalMap(Class<? extends Enum<?>> valueType, V virginValue) {
map = new HashMap<Integer, V>();
Enum<?>[] enums = valueType.getEnumConstants();
for (int i = 0; i < enums.length; i++) {
put(enums[i].ordinal(), virginValue);
}
}
public OrdinalMap(Class<? extends Enum<?>> valueType) {
this(valueType, null);
}
public V put(Integer key, V value) {
return map.put(key, value);
}
public V get(Object o) {
return map.get(o);
}
public Set<Entry<Integer, V>> entrySet() {
return map.entrySet();
}
}
I want to make dispatchEvent faster (less iterations). It has too many iterations because of registerListener
There are event handler methods inside of all of the other priorities, when they shouldn’t be there. I can’t figure out why there are there, but I’m certain it’s in registerListener. Because they are inside all priorities, I have to use this check:
if (mapping.getKey().getAnnotation(EventHandler.class).priority().ordinal() == entry.getKey()) {
Which makes it even slower.
@Override
public void dispatchEvent(Event event) {
OrdinalMap<Map<Method, EventListener>> priorityMap = getRegistry().get(event.getClass());
if (priorityMap != null) {
CancellableEvent cancellableEvent = null;
boolean cancellable;
if (cancellable = event instanceof CancellableEvent) {
cancellableEvent = (CancellableEvent) event;
if (cancellableEvent.isCancelled()) return;
}
try {
for (Entry<Integer, Map<Method, EventListener>> entry : priorityMap.entrySet()) {
for (Entry<Method, EventListener> mapping : entry.getValue().entrySet()) {
if (mapping.getKey().getAnnotation(EventHandler.class).priority().ordinal() == entry.getKey()) {
mapping.getKey().invoke(mapping.getValue(), event);
if (cancellable && cancellableEvent.isCancelled()) return;
}
}
}
} catch (InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
@Override
public void registerListener(EventListener listener) {
for (Method method : listener.getClass().getMethods()) {
EventHandler handler = method.getAnnotation(EventHandler.class);
if (handler != null) {
Class<?>[] parameters = method.getParameterTypes();
if (parameters.length == 1) {
@SuppressWarnings("unchecked")
Class<? extends Event> event = (Class<? extends Event>) parameters[0];
EventPriority priority = handler.priority();
OrdinalMap<Map<Method, EventListener>> priorityMap = getRegistry().get(event);
if (priorityMap == null) {
priorityMap = new OrdinalMap<Map<Method, EventListener>>(EventPriority.class, (Map<Method, EventListener>) new HashMap<Method, EventListener>());
}
Map<Method, EventListener> methodMap = priorityMap.get(priority.ordinal());
methodMap.put(method, listener);
priorityMap.put(priority.ordinal(), methodMap);
getRegistry().put(event, priorityMap);
}
}
}
}
You are using maps so consider using thiere benefits instead of iterating on all entries
comparing two hahmap keys to find a match is not really a good idea.
how about the following, i hope i didn’t make any thinking mistake
here you no longer have the outer for loop
My bad, didn’t pay attention enough …
But the idea is the same, when using hashmaps / hashsets one should always try to use get / contains instead of iterating, and for that one needs to design the registry the way that makes this prossible
Would the following work for your needs ? (untested)
and