mirror of
https://github.com/NoCheatPlus/NoCheatPlus.git
synced 2024-10-06 10:27:26 +02:00
Implement more efficient handles.
This commit is contained in:
parent
2bf3e14ab9
commit
d6bb1e84bc
@ -4,11 +4,12 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import fr.neatmonster.nocheatplus.components.registry.event.GenericInstanceHandle;
|
||||
import fr.neatmonster.nocheatplus.components.registry.event.GenericInstanceHandle.ReferenceCountHandle;
|
||||
import fr.neatmonster.nocheatplus.components.registry.event.IGenericInstanceHandle;
|
||||
import fr.neatmonster.nocheatplus.components.registry.event.IGenericInstanceRegistryListener;
|
||||
import fr.neatmonster.nocheatplus.components.registry.event.IUnregisterGenericInstanceListener;
|
||||
@ -17,12 +18,17 @@ import fr.neatmonster.nocheatplus.logging.details.ILogString;
|
||||
|
||||
public class DefaultGenericInstanceRegistry implements GenericInstanceRegistry, IUnregisterGenericInstanceListener {
|
||||
|
||||
// TODO: Test cases.
|
||||
|
||||
/** Storage for generic instances registration. */
|
||||
private final Map<Class<?>, Object> instances = new HashMap<Class<?>, Object>();
|
||||
|
||||
/** Listeners for registry events. */
|
||||
private final Map<Class<?>, Collection<IGenericInstanceRegistryListener<?>>> listeners = new HashMap<Class<?>, Collection<IGenericInstanceRegistryListener<?>>>();
|
||||
|
||||
/** Owned handles by the class they have been registered for. */
|
||||
private final Map<Class<?>, IGenericInstanceHandle<?>> uniqueHandles = new LinkedHashMap<Class<?>, IGenericInstanceHandle<?>>();
|
||||
|
||||
/** Handles created within this class, that have to be detached. */
|
||||
private final Set<IGenericInstanceHandle<?>> ownedHandles = new LinkedHashSet<IGenericInstanceHandle<?>>();
|
||||
|
||||
@ -47,8 +53,9 @@ public class DefaultGenericInstanceRegistry implements GenericInstanceRegistry,
|
||||
listeners.remove(registeredFor);
|
||||
}
|
||||
}
|
||||
if ((listener instanceof IGenericInstanceHandle<?>) && ownedHandles.contains(listener)) {
|
||||
if ((listener instanceof ReferenceCountHandle<?>) && ownedHandles.contains(listener)) {
|
||||
ownedHandles.remove(listener);
|
||||
uniqueHandles.remove(registeredFor);
|
||||
((IGenericInstanceHandle<?>) listener).disableHandle();
|
||||
}
|
||||
}
|
||||
@ -114,22 +121,21 @@ public class DefaultGenericInstanceRegistry implements GenericInstanceRegistry,
|
||||
|
||||
@Override
|
||||
public <T> IGenericInstanceHandle<T> getGenericInstanceHandle(Class<T> registeredFor) {
|
||||
/*
|
||||
* More efficient should be to return a wrapper for a unique instance,
|
||||
* for which disableHandle runs once, so only one listener per
|
||||
* registered class is necessary, which then uses reference counting for
|
||||
* actual removal. That's double-wrapped then (returned instance disable
|
||||
* once -> reference counting instance -> actual instance).
|
||||
*/
|
||||
final IGenericInstanceHandle<T> handle = new GenericInstanceHandle<T>(registeredFor, this, this);
|
||||
ownedHandles.add(handle);
|
||||
Collection<IGenericInstanceRegistryListener<?>> registered = listeners.get(registeredFor);
|
||||
if (registered == null) {
|
||||
registered = new HashSet<IGenericInstanceRegistryListener<?>>();
|
||||
listeners.put(registeredFor, registered);
|
||||
@SuppressWarnings("unchecked")
|
||||
ReferenceCountHandle<T> handle = (ReferenceCountHandle<T>) uniqueHandles.get(registeredFor);
|
||||
if (handle == null) {
|
||||
handle = new ReferenceCountHandle<T>(registeredFor, this, this);
|
||||
ownedHandles.add(handle);
|
||||
uniqueHandles.put(registeredFor, handle);
|
||||
Collection<IGenericInstanceRegistryListener<?>> registered = listeners.get(registeredFor);
|
||||
if (registered == null) {
|
||||
registered = new HashSet<IGenericInstanceRegistryListener<?>>();
|
||||
listeners.put(registeredFor, registered);
|
||||
}
|
||||
registered.add((IGenericInstanceRegistryListener<?>) handle);
|
||||
}
|
||||
registered.add((IGenericInstanceRegistryListener<?>) handle);
|
||||
return handle;
|
||||
// else: no need to register.
|
||||
return handle.getNewHandle();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
|
@ -13,7 +13,82 @@ import fr.neatmonster.nocheatplus.components.registry.GenericInstanceRegistry;
|
||||
public class GenericInstanceHandle<T> implements IGenericInstanceRegistryListener<T>, IGenericInstanceHandle<T> {
|
||||
|
||||
// TODO: <? extends T> ?
|
||||
// TODO: Might move to NCPPlugin, or later split (mostly) interface based api from default implementations.
|
||||
|
||||
/**
|
||||
* Delegates getHandle, disables the parent only once (meant for reference
|
||||
* counting).
|
||||
*
|
||||
* @author asofold
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public static class ParentDelegateHandle<T> implements IGenericInstanceHandle<T> {
|
||||
|
||||
private final IGenericInstanceHandle<T> parent;
|
||||
private boolean disabled = false;
|
||||
|
||||
public ParentDelegateHandle(Class<T> registeredFor, GenericInstanceRegistry registry,
|
||||
IGenericInstanceHandle<T> parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getHandle() {
|
||||
if (disabled) {
|
||||
throw new RuntimeException("Already disabled.");
|
||||
}
|
||||
else {
|
||||
return parent.getHandle();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableHandle() {
|
||||
if (!disabled) {
|
||||
disabled = true;
|
||||
parent.disableHandle();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow fetching PrarentDelegate instances, increasing reference count with
|
||||
* each returned one. Really unregister only with reaching a count of zero
|
||||
* on disableHandle. This way only one instance needs to be updated.
|
||||
*
|
||||
* @author asofold
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public static class ReferenceCountHandle<T> extends GenericInstanceHandle<T> {
|
||||
|
||||
private int references = 0;
|
||||
|
||||
public ReferenceCountHandle(Class<T> registeredFor, GenericInstanceRegistry registry,
|
||||
IUnregisterGenericInstanceListener unregister) {
|
||||
super(registeredFor, registry, unregister);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableHandle() {
|
||||
references --;
|
||||
// Only really unregister once.
|
||||
if (references == 0) {
|
||||
super.disableHandle();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a new instance referencing this one.
|
||||
* @return
|
||||
*/
|
||||
public IGenericInstanceHandle<T> getNewHandle() {
|
||||
references ++;
|
||||
return new ParentDelegateHandle<T>(getRegisteredFor(), getRegistry(), this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private GenericInstanceRegistry registry;
|
||||
private IUnregisterGenericInstanceListener unregister;
|
||||
@ -22,8 +97,6 @@ public class GenericInstanceHandle<T> implements IGenericInstanceRegistryListene
|
||||
private boolean initialized = false;
|
||||
private boolean disabled = false;
|
||||
|
||||
// TODO: Remove method?
|
||||
|
||||
/**
|
||||
* Note that this doesn't register with the registry, as the registry may
|
||||
* return unique handles on request rather.
|
||||
@ -81,9 +154,23 @@ public class GenericInstanceHandle<T> implements IGenericInstanceRegistryListene
|
||||
handle = null;
|
||||
registeredFor = null;
|
||||
registry = null;
|
||||
unregister.unregisterGenericInstanceListener(registeredFor, this);
|
||||
if (unregister != null) {
|
||||
unregister.unregisterGenericInstanceListener(registeredFor, this);
|
||||
}
|
||||
unregister = null;
|
||||
}
|
||||
}
|
||||
|
||||
public Class<T> getRegisteredFor() {
|
||||
return registeredFor;
|
||||
}
|
||||
|
||||
public GenericInstanceRegistry getRegistry() {
|
||||
return registry;
|
||||
}
|
||||
|
||||
public IUnregisterGenericInstanceListener getUnregister() {
|
||||
return unregister;
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user