[DEV] add some generic code

This commit is contained in:
Edouard DUPIN 2021-06-04 15:45:13 +02:00
parent 722e6fe5cf
commit 70755dbbf4
5 changed files with 69 additions and 93 deletions

View File

@ -13,8 +13,8 @@ import org.atriasoft.esignal.internal.ConnectedElementDynamic;
* @param <T> generic Runnable, Consumer, or BiConsumer template... * @param <T> generic Runnable, Consumer, or BiConsumer template...
*/ */
public class GenericSignal<T> implements ConnectionRemoveInterface { public class GenericSignal<T> implements ConnectionRemoveInterface {
List<ConnectedElement<T>> data = new ArrayList<>();
protected List<ConnectedElement<T>> data = new ArrayList<>();
public void clear() { public void clear() {
List<ConnectedElement<T>> data2 = this.data; List<ConnectedElement<T>> data2 = this.data;
synchronized(this.data) { synchronized(this.data) {
@ -50,9 +50,9 @@ public class GenericSignal<T> implements ConnectionRemoveInterface {
} }
return out; return out;
} }
public void connectAutoRemoveObject(final Object reference, final T function) { public void connectAutoRemoveObject(final Object object, final T function) {
synchronized(this.data) { synchronized(this.data) {
this.data.add(new ConnectedElementDynamic<T>(reference, function)); this.data.add(new ConnectedElementDynamic<T>(object, function));
} }
} }
@ -70,8 +70,42 @@ public class GenericSignal<T> implements ConnectionRemoveInterface {
} }
} }
protected List<ConnectedElement<T>> getACleanedList() {
// first clean the list
cleanedList();
// get a copy of elements
List<ConnectedElement<T>> out = null;
// clean the list:
synchronized(this.data) {
// simple optimization:
if (this.data.isEmpty()) {
return null;
}
// clone the list to permit to have asynchronous remove call
out = new ArrayList<>(this.data);
}
return out;
}
protected void cleanedList() {
// clean the list:
synchronized(this.data) {
final Iterator<ConnectedElement<T>> iterator = this.data.iterator();
while (iterator.hasNext()) {
final ConnectedElement<T> elem = iterator.next();
Object tmpObject = elem.getConsumer();
if (tmpObject == null) {
elem.disconnect();
iterator.remove();
}
}
}
}
public int size() { public int size() {
return this.data.size(); return this.data.size();
} }
public int sizeCleaned() {
cleanedList();
return this.data.size();
}
} }

View File

@ -53,42 +53,20 @@ import org.atriasoft.esignal.internal.ConnectedElement;
*/ */
public class Signal<T> extends GenericSignal<Consumer<T>> { public class Signal<T> extends GenericSignal<Consumer<T>> {
public void emit(final T value) { public void emit(final T value) {
List<ConnectedElement<Consumer<T>>> tmp; List<ConnectedElement<Consumer<T>>> tmp = getACleanedList();
// clean the list: if (tmp == null) {
synchronized(this.data) {
final Iterator<ConnectedElement<Consumer<T>>> iterator = this.data.iterator();
while (iterator.hasNext()) {
final ConnectedElement<Consumer<T>> elem = iterator.next();
Object tmpObject = elem.getConsumer();
if (tmpObject == null) {
elem.disconnect();
iterator.remove();
}
}
// simple optimization:
if (this.data.isEmpty()) {
return; return;
} }
// clone the list to permit to have asynchronous remove call
tmp = new ArrayList<>(this.data);
}
// real call elements // real call elements
{
final Iterator<ConnectedElement<Consumer<T>>> iterator = tmp.iterator(); final Iterator<ConnectedElement<Consumer<T>>> iterator = tmp.iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
final ConnectedElement<Consumer<T>> elem = iterator.next(); final ConnectedElement<Consumer<T>> elem = iterator.next();
Consumer<T> tmpObject = elem.getConsumer(); Consumer<T> tmpObject = elem.getConsumer();
if (tmpObject == null) { if (tmpObject == null) {
// Not a dead code, but very hard to simply test it.
continue; continue;
} }
tmpObject.accept(value); tmpObject.accept(value);
} }
} }
}
@Override
public int size() {
return this.data.size();
}
} }

View File

@ -55,27 +55,11 @@ import org.atriasoft.esignal.internal.ConnectedElement;
*/ */
public class Signal2<T, U> extends GenericSignal<BiConsumer<T, U>> { public class Signal2<T, U> extends GenericSignal<BiConsumer<T, U>> {
public void emit(final T valueT, final U valueU) { public void emit(final T valueT, final U valueU) {
List<ConnectedElement<BiConsumer<T, U>>> tmp; List<ConnectedElement<BiConsumer<T, U>>> tmp = getACleanedList();
// clean the list: if (tmp == null) {
synchronized(this.data) {
final Iterator<ConnectedElement<BiConsumer<T, U>>> iterator = this.data.iterator();
while (iterator.hasNext()) {
final ConnectedElement<BiConsumer<T, U>> elem = iterator.next();
Object tmpObject = elem.getConsumer();
if (tmpObject == null) {
elem.disconnect();
iterator.remove();
}
}
// simple optimization:
if (this.data.isEmpty()) {
return; return;
} }
// clone the list to permit to have asynchronous remove call
tmp = new ArrayList<>(this.data);
}
// real call elements // real call elements
{
final Iterator<ConnectedElement<BiConsumer<T, U>>> iterator = tmp.iterator(); final Iterator<ConnectedElement<BiConsumer<T, U>>> iterator = tmp.iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
final ConnectedElement<BiConsumer<T, U>> elem = iterator.next(); final ConnectedElement<BiConsumer<T, U>> elem = iterator.next();
@ -86,6 +70,5 @@ public class Signal2<T, U> extends GenericSignal<BiConsumer<T, U>> {
tmpObject.accept(valueT, valueU); tmpObject.accept(valueT, valueU);
} }
} }
}
} }

View File

@ -51,27 +51,11 @@ import org.atriasoft.esignal.internal.ConnectedElement;
public class SignalEmpty extends GenericSignal<Runnable> { public class SignalEmpty extends GenericSignal<Runnable> {
public void emit() { public void emit() {
List<ConnectedElement<Runnable>> tmp; List<ConnectedElement<Runnable>> tmp = getACleanedList();
// clean the list: if (tmp == null) {
synchronized(this.data) {
final Iterator<ConnectedElement<Runnable>> iterator = this.data.iterator();
while (iterator.hasNext()) {
final ConnectedElement<Runnable> elem = iterator.next();
Object tmpObject = elem.getConsumer();
if (tmpObject == null) {
elem.disconnect();
iterator.remove();
}
}
// simple optimization:
if (this.data.isEmpty()) {
return; return;
} }
// clone the list to permit to have asynchronous remove call
tmp = new ArrayList<>(this.data);
}
// real call elements // real call elements
{
final Iterator<ConnectedElement<Runnable>> iterator = tmp.iterator(); final Iterator<ConnectedElement<Runnable>> iterator = tmp.iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
final ConnectedElement<Runnable> elem = iterator.next(); final ConnectedElement<Runnable> elem = iterator.next();
@ -82,6 +66,5 @@ public class SignalEmpty extends GenericSignal<Runnable> {
tmpObject.run(); tmpObject.run();
} }
} }
}
} }

View File

@ -117,9 +117,7 @@ public class TestSignalEmpty {
receiver = null; receiver = null;
Assertions.assertEquals(1, sender.signalEvent.size()); Assertions.assertEquals(1, sender.signalEvent.size());
System.gc(); System.gc();
Assertions.assertEquals(0, sender.signalEvent.sizeCleaned());
sender.sendEvent();
Assertions.assertEquals(0, sender.signalEvent.size());
Log.warning("Test 1 [ END ]"); Log.warning("Test 1 [ END ]");
} }