Skip to content

Commit

Permalink
Minor Optimizations for MangoBot
Browse files Browse the repository at this point in the history
  • Loading branch information
RealMangorage committed May 22, 2024
1 parent 314cce0 commit 836e263
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 154 deletions.
2 changes: 1 addition & 1 deletion src/main/java/org/mangorage/mboteventbus/base/Event.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@

package org.mangorage.mboteventbus.base;

public abstract class Event {
public class Event {
}
94 changes: 28 additions & 66 deletions src/main/java/org/mangorage/mboteventbus/base/EventBus.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@
import org.mangorage.mboteventbus.impl.IEventBus;
import org.mangorage.mboteventbus.impl.IListenerList;

import java.util.ArrayList;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Semaphore;
import java.util.function.Consumer;

public final class EventBus implements IEventBus {
Expand All @@ -39,47 +40,52 @@ private record ListenerKey(Class<?> eventClass, Class<?> genericClass) {
}

private final Map<ListenerKey, IListenerList<? extends Event>> LISTENERS = new ConcurrentHashMap<>();
private final Semaphore writeLock = new Semaphore(1, true);


@SuppressWarnings("unchecked")
public <T extends Event> void addListener(int priority, Class<T> eventClass, Consumer<T> eventConsumer) {
IListenerList<T> list = (IListenerList<T>) getListenerList(eventClass, null);
IListenerList<T> list = getListenerList(eventClass, null);
if (list == null) return;
list.register(eventConsumer, "default", priority);
list.register(eventConsumer, "default -> " + eventClass, priority);
}


@SuppressWarnings("unchecked")
public <T extends GenericEvent<? extends G>, G> void addGenericListener(int priority, Class<G> genericClassFilter, Class<T> eventType, Consumer<T> genericEventListener) {
IListenerList<T> list = (IListenerList<T>) getListenerList(eventType, genericClassFilter);
IListenerList<T> list = getListenerList(eventType, genericClassFilter);
if (list == null) return;
list.register(genericEventListener, "default", priority);
list.register(genericEventListener, "default -> " + eventType + " -> " + genericClassFilter, priority);
}

public void post(Event event) {
public <T extends Event> void post(T event) {
Class<?> genericType = null;
if (event instanceof GenericEvent<?> genericEvent)
genericType = genericEvent.getGenericType();

var listeners = getListenerList(event.getClass(), genericType);
if (listeners != null)
listeners.accept(event);
writeLock.acquireUninterruptibly();
IListenerList<T> listeners = getListenerList(getEventClass(event), genericType);
writeLock.release();
if (listeners != null) listeners.accept(event);
}

private IListenerList<?> getListenerList(Class<?> eventClass, Class<?> genericClass) {
@SuppressWarnings("unchecked")
private <T extends Event> Class<T> getEventClass(T event) {
return (Class<T>) event.getClass();
}

@SuppressWarnings("unchecked")
private <T extends Event> IListenerList<T> getListenerList(Class<T> eventClass, Class<?> genericClass) {
var list = getListenerListInternal(eventClass, genericClass);
return list == null ? null : (IListenerList<T>) list;
}

@SuppressWarnings("unchecked")
private IListenerList<?> getListenerListInternal(Class<?> eventClass, Class<?> genericClass) {
var key = new ListenerKey(eventClass, genericClass);
var list = LISTENERS.get(key);
if (list != null) {
return list;
}
if (list != null) return list;

if (eventClass == Object.class)
if (eventClass == Object.class || eventClass == Event.class && genericClass != null)
return null;

if (eventClass == Event.class && genericClass != null)
return null;

return LISTENERS.computeIfAbsent(key, e -> new ListenerListImpl<>(new ArrayList<>(), getListenerList(eventClass.getSuperclass(), genericClass)));
return LISTENERS.computeIfAbsent(key, e -> new ListenerListImpl<>(new CopyOnWriteArrayList<>(), (IListenerList<Event>) getListenerListInternal(eventClass.getSuperclass(), genericClass)));
}

@Override
Expand All @@ -91,48 +97,4 @@ public void startup() {
public void shutdown() {

}


public static class MyEvent extends Event {
public MyEvent() {
//super(Integer.class);
}
}

public static class MyBetterEvent extends MyEvent {
}

public static class MyCrazyEvent extends MyBetterEvent {
}


public static void main(String[] args) {
IEventBus bus = create();


// bus.addGenericListener(10, Integer.class, MyEvent.class, e -> {
// System.out.println("Sweet -> " + e.getClass());
// });
//
bus.addGenericListener(10, Integer.class, GenericEvent.class, e -> {
System.out.println("Generic -> " + e.getClass());

});

bus.addListener(10, Event.class, e -> {
System.out.println(e.getClass());
});

bus.addListener(10, MyEvent.class, e -> {
System.out.println("Sweeet! -> " + e.getClass());
});

bus.post(new MyBetterEvent());
bus.post(new MyEvent());
bus.post(new MyCrazyEvent());
bus.post(new GenericEvent<>(Integer.class) {
});

System.out.println("END");
}
}
33 changes: 0 additions & 33 deletions src/main/java/org/mangorage/mboteventbus/base/ListenerKey.java

This file was deleted.

48 changes: 12 additions & 36 deletions src/main/java/org/mangorage/mboteventbus/base/ListenerListImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,80 +25,56 @@
import org.mangorage.basicutils.misc.Lazy;
import org.mangorage.mboteventbus.impl.IListenerList;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.function.Consumer;
import java.util.stream.Stream;

@SuppressWarnings("unchecked")
public class ListenerListImpl<T> implements IListenerList<T> {
private final List<Listener<T>> backingList;
private final IListenerList<?> parent;
private final Set<IListenerList<?>> children = new HashSet<>();
private final Set<IListenerList<T>> children = new CopyOnWriteArraySet<>();
private final Lazy<Listener<T>[]> listeners;

public ListenerListImpl(List<Listener<T>> backingList, IListenerList<?> parent) {
public ListenerListImpl(List<Listener<T>> backingList, IListenerList<T> parent) {
this.backingList = backingList;
this.parent = parent;
if (parent != null) parent.addChild(this);

this.listeners = Lazy.concurrentOf(() -> {
if (parent != null) {
return Stream.of(backingList, List.of(parent.getListeners()))
.flatMap(List::stream)
.sorted()
.toArray(Listener[]::new);
}

return backingList.toArray(Listener[]::new);
});
this.listeners = Lazy.concurrentOf(() -> parent == null ? backingList.toArray(Listener[]::new) : Stream.of(backingList, List.of(parent.getListeners()))
.flatMap(List::stream)
.sorted()
.toArray(Listener[]::new));
}

/**
* @param child
*/
@Override
public void addChild(IListenerList<?> child) {
public void addChild(IListenerList<T> child) {
children.add(child);
}

/**
* @param event
*/
@Override
public void accept(Event event) {
public void accept(T event) {
for (Listener<T> listener : getListeners()) {
listener.consumer().accept((T) event);
listener.consumer().accept(event);
}
}

/**
* @param eventConsumer
* @param name
* @param priority
*/
@Override
public void register(Consumer<T> eventConsumer, String name, int priority) {
backingList.add(new Listener<>(priority, name, eventConsumer));
if (parent != null) parent.invalidate();
children.forEach(IListenerList::invalidate);
if (parent != null) parent.invalidate();
}

/**
* @return
*/
@Override
public Listener<T>[] getListeners() {
return listeners.get();
}

/**
*
*/
@Override
public void invalidate() {
listeners.invalidate();
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public interface IEventBus {

<T extends GenericEvent<? extends G>, G> void addGenericListener(int priority, Class<G> genericClass, Class<T> genericEvent, Consumer<T> genericEventListener);

void post(Event event);
<T extends Event> void post(T event);
void startup();
void shutdown();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,16 @@

package org.mangorage.mboteventbus.impl;

import org.mangorage.mboteventbus.base.Event;
import org.mangorage.mboteventbus.base.Listener;

import java.util.function.Consumer;

public interface IListenerList<T> {
void accept(Event event);
void accept(T event);
void register(Consumer<T> eventConsumer, String name, int priority);

Listener<T>[] getListeners();

void invalidate();

void addChild(IListenerList<?> child);
void addChild(IListenerList<T> child);
}
40 changes: 27 additions & 13 deletions src/test/java/org/mangorage/mangobot/test/EventBusTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,37 +26,51 @@
import org.mangorage.mboteventbus.base.Event;
import org.mangorage.mboteventbus.base.EventBus;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class EventBusTest {

public static class MyEvent extends Event {
}

public static class MyOther extends MyEvent {
}


public static final ExecutorService ex = Executors.newWorkStealingPool();

public static void main(String[] args) {

public static void main(String[] args) throws InterruptedException {
var bus = EventBus.create();

var registration = TimedTest.of(() -> {
for (int i = 0; i < 10000; i++) {
for (int i = 0; i < 1000; i++) {
bus.addListener(10, Event.class, e -> {
});
bus.addListener(10, MyEvent.class, e -> {
bus.addListener(10, MyOther.class, e -> {
});
}
});

long amount = 100000;
var post = TimedTest.of(() -> {
bus.post(new MyEvent());
for (int i = 0; i < amount; i++) {
bus.post(new MyOther());
bus.post(new Event());
}
});

List<MyEvent> myEvents = new ArrayList<>();
for (int i = 0; i < amount; i++)
myEvents.add(new MyEvent());

myEvents.stream().parallel().forEach(bus::post);

System.out.println("Registration time for 1 listener -> " + registration.getResult());
long total = 0;
long amount = 10000;

for (int i = 0; i < amount; i++) {
var result = post.getResult();
System.out.println("Post time for Post #%s -> ".formatted(i) + result);
total += result;
}
System.out.println("AVG -> " + total / amount);
System.out.println("AVG -> " + post.getResult() / amount);
var a = 1;
}
}

0 comments on commit 836e263

Please sign in to comment.