summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Young <consult.awy@gmail.com>2016-04-18 16:37:46 (GMT)
committerAlan Young <consult.awy@gmail.com>2016-04-20 16:29:51 (GMT)
commit9d50093bee736d2b7b43756e9a41cfafbd568ee2 (patch)
tree50923023315027b6a099f7349506868d58b4d736
parent82f43f69b1cdb1d2f6cd11c64a71dc99c8533d5a (diff)
downloadstroke-9d50093bee736d2b7b43756e9a41cfafbd568ee2.zip
stroke-9d50093bee736d2b7b43756e9a41cfafbd568ee2.tar.bz2
Rework Signals for time and space optimizations
Each Signal* class extends BaseSignal. Each Slot* class extends BaseSlot. BaseSignal manages the set of binds associated with it via addBind() and getBinds() which are called from Signal*. It is optimized for the cases of zero or one bind, only allocating a HashMap to hold a larger set when needed. The interaction with SignalConnection to handle disconnection is effected via a callback interface rather than another Signal. Change-Id: Ifa44c1eb40b778c303db947a6e74fe20d1b41a90
-rw-r--r--src/com/isode/stroke/muc/MUCImpl.java2
-rw-r--r--src/com/isode/stroke/signals/BaseSignal.java62
-rw-r--r--src/com/isode/stroke/signals/BaseSlot.java9
-rw-r--r--src/com/isode/stroke/signals/Signal.java35
-rw-r--r--src/com/isode/stroke/signals/Signal1.java31
-rw-r--r--src/com/isode/stroke/signals/Signal2.java31
-rw-r--r--src/com/isode/stroke/signals/Signal3.java39
-rw-r--r--src/com/isode/stroke/signals/Signal4.java40
-rw-r--r--src/com/isode/stroke/signals/Signal7.java38
-rw-r--r--src/com/isode/stroke/signals/SignalConnection.java17
-rw-r--r--src/com/isode/stroke/signals/Slot.java2
-rw-r--r--src/com/isode/stroke/signals/Slot1.java2
-rw-r--r--src/com/isode/stroke/signals/Slot2.java2
-rw-r--r--src/com/isode/stroke/signals/Slot3.java2
-rw-r--r--src/com/isode/stroke/signals/Slot4.java2
-rw-r--r--src/com/isode/stroke/signals/Slot7.java2
16 files changed, 137 insertions, 179 deletions
diff --git a/src/com/isode/stroke/muc/MUCImpl.java b/src/com/isode/stroke/muc/MUCImpl.java
index 444b331..26be309 100644
--- a/src/com/isode/stroke/muc/MUCImpl.java
+++ b/src/com/isode/stroke/muc/MUCImpl.java
@@ -724,7 +724,7 @@ public class MUCImpl extends MUC {
@Override
public void disconnect() {
if (scopedConnection_ != null) {
- scopedConnection_.onDestroyed.emit();
+ scopedConnection_.disconnect();
scopedConnection_ = null;
}
}
diff --git a/src/com/isode/stroke/signals/BaseSignal.java b/src/com/isode/stroke/signals/BaseSignal.java
new file mode 100644
index 0000000..de1bd6e
--- /dev/null
+++ b/src/com/isode/stroke/signals/BaseSignal.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015, Isode Limited, London, England.
+ * All rights reserved.
+ */
+package com.isode.stroke.signals;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/* package */ abstract class BaseSignal implements SignalConnection.DisconnectListener {
+
+ // Optimized for the case of 0 or 1 bind
+ private SignalConnection connection_;
+ private BaseSlot bind_;
+ private Map<SignalConnection, BaseSlot> binds_;
+
+ protected final synchronized SignalConnection addBind(final BaseSlot bind) {
+ final SignalConnection connection = new SignalConnection(this);
+ if (binds_ != null) {
+ binds_.put(connection, bind);
+ } else if (connection_ != null) {
+ binds_ = new HashMap<SignalConnection, BaseSlot>();
+ binds_.put(connection_, bind_);
+ connection_ = null;
+ bind_ = null;
+ binds_.put(connection, bind);
+ } else {
+ connection_ = connection;
+ bind_ = bind;
+ }
+ return connection;
+ }
+
+ protected final synchronized BaseSlot[] getBinds() {
+ if (binds_ != null) {
+ return binds_.values().toArray(new BaseSlot[binds_.size()]);
+ } else if (connection_ != null) {
+ return new BaseSlot[]{bind_};
+ } else {
+ return null; // return null rather than allocate an empty array
+ }
+ }
+
+ @Override
+ public final synchronized void onSignalConnectionDisconnect(final SignalConnection connection) {
+ if (binds_ != null) {
+ binds_.remove(connection);
+ } else if (connection_ == connection) {
+ connection_ = null;
+ bind_ = null;
+ }
+ }
+
+ public final synchronized void disconnectAll() {
+ if (binds_ != null) {
+ binds_.clear();
+ } else {
+ connection_ = null;
+ bind_ = null;
+ }
+ }
+}
diff --git a/src/com/isode/stroke/signals/BaseSlot.java b/src/com/isode/stroke/signals/BaseSlot.java
new file mode 100644
index 0000000..9b8ac13
--- /dev/null
+++ b/src/com/isode/stroke/signals/BaseSlot.java
@@ -0,0 +1,9 @@
+/*
+ * Copyright (c) 2015, Isode Limited, London, England.
+ * All rights reserved.
+ */
+package com.isode.stroke.signals;
+
+/* package */ interface BaseSlot {
+
+}
diff --git a/src/com/isode/stroke/signals/Signal.java b/src/com/isode/stroke/signals/Signal.java
index cfa8665..1821cb0 100644
--- a/src/com/isode/stroke/signals/Signal.java
+++ b/src/com/isode/stroke/signals/Signal.java
@@ -1,31 +1,17 @@
/*
- * Copyright (c) 2010, Isode Limited, London, England.
+ * Copyright (c) 2010-2015, Isode Limited, London, England.
* All rights reserved.
*/
package com.isode.stroke.signals;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
/**
* An approximation of the boost::signals system, although a little more warty.
*/
-public class Signal {
-
- private final Map<SignalConnection, Slot> binds_ = Collections.synchronizedMap(new HashMap<SignalConnection, Slot>());
+public final class Signal extends BaseSignal {
public SignalConnection connect(Slot bind) {
- final SignalConnection connection = new SignalConnection();
- binds_.put(connection, bind);
- connection.onDestroyed.connectWithoutReturn(new Slot() {
-
- public void call() {
- binds_.remove(connection);
- }
- });
- return connection;
+ return addBind(bind);
}
public SignalConnection connect(final Signal target) {
@@ -36,19 +22,12 @@ public class Signal {
});
}
- void connectWithoutReturn(Slot bind) {
- binds_.put(null, bind);
- }
-
public void emit() {
- ArrayList<Slot> binds = new ArrayList<Slot>();
- binds.addAll(binds_.values());
- for (Slot bind : binds) {
- bind.call();
+ final BaseSlot[] binds = getBinds();
+ if (binds == null) {return;}
+ for (BaseSlot bind : binds) {
+ ((Slot)bind).call();
}
}
- public void disconnectAll() {
- binds_.clear();
- }
}
diff --git a/src/com/isode/stroke/signals/Signal1.java b/src/com/isode/stroke/signals/Signal1.java
index c799d4c..9787096 100644
--- a/src/com/isode/stroke/signals/Signal1.java
+++ b/src/com/isode/stroke/signals/Signal1.java
@@ -1,36 +1,25 @@
/*
- * Copyright (c) 2010, Isode Limited, London, England.
+ * Copyright (c) 2010-2015, Isode Limited, London, England.
* All rights reserved.
*/
package com.isode.stroke.signals;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
/**
* An approximation of the boost::signals system, although a little more warty.
*/
-public class Signal1<T1> {
- private final Map<SignalConnection, Slot1<T1> > binds_ = Collections.synchronizedMap(new HashMap<SignalConnection, Slot1<T1> >());
+public final class Signal1<T1> extends BaseSignal {
public SignalConnection connect(Slot1<T1> bind) {
- final SignalConnection connection = new SignalConnection();
- binds_.put(connection, bind);
- connection.onDestroyed.connect(new Slot() {
- public void call() {
- binds_.remove(connection);
- }
- });
- return connection;
+ return addBind(bind);
}
+ @SuppressWarnings("unchecked")
public void emit(T1 p1) {
- ArrayList<Slot1<T1>> binds = new ArrayList<Slot1<T1>>();
- binds.addAll(binds_.values());
- for (Slot1<T1> bind : binds) {
- bind.call(p1);
+ final BaseSlot[] binds = getBinds();
+ if (binds == null) {return;}
+ for (BaseSlot bind : binds) {
+ ((Slot1<T1>)bind).call(p1);
}
}
@@ -41,8 +30,4 @@ public class Signal1<T1> {
}
});
}
-
- public void disconnectAll() {
- binds_.clear();
- }
}
diff --git a/src/com/isode/stroke/signals/Signal2.java b/src/com/isode/stroke/signals/Signal2.java
index fa3c4b5..72c9de0 100644
--- a/src/com/isode/stroke/signals/Signal2.java
+++ b/src/com/isode/stroke/signals/Signal2.java
@@ -1,40 +1,25 @@
/*
- * Copyright (c) 2010, Isode Limited, London, England.
+ * Copyright (c) 2010-2015, Isode Limited, London, England.
* All rights reserved.
*/
package com.isode.stroke.signals;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
/**
* An approximation of the boost::signals system, although a little more warty.
*/
-public class Signal2<T1, T2> {
- private final Map<SignalConnection, Slot2<T1, T2> > binds_ = Collections.synchronizedMap(new HashMap<SignalConnection, Slot2<T1, T2> >());
+public class Signal2<T1, T2> extends BaseSignal {
public SignalConnection connect(Slot2<T1, T2> bind) {
- final SignalConnection connection = new SignalConnection();
- binds_.put(connection, bind);
- connection.onDestroyed.connect(new Slot() {
- public void call() {
- binds_.remove(connection);
- }
- });
- return connection;
+ return addBind(bind);
}
+ @SuppressWarnings("unchecked")
public void emit(T1 p1, T2 p2) {
- ArrayList<Slot2<T1,T2>> binds = new ArrayList<Slot2<T1, T2>>();
- binds.addAll(binds_.values());
- for (Slot2<T1, T2> bind : binds) {
- bind.call(p1, p2);
+ final BaseSlot[] binds = getBinds();
+ if (binds == null) {return;}
+ for (BaseSlot bind : binds) {
+ ((Slot2<T1, T2>)bind).call(p1, p2);
}
}
-
- public void disconnectAll() {
- binds_.clear();
- }
}
diff --git a/src/com/isode/stroke/signals/Signal3.java b/src/com/isode/stroke/signals/Signal3.java
index b9151dc..014f047 100644
--- a/src/com/isode/stroke/signals/Signal3.java
+++ b/src/com/isode/stroke/signals/Signal3.java
@@ -1,15 +1,10 @@
/*
- * Copyright (c) 2012, Isode Limited, London, England.
+ * Copyright (c) 2010-2015, Isode Limited, London, England.
* All rights reserved.
*/
package com.isode.stroke.signals;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
/**
* An approximation of the boost::signals system with 3 parameters
@@ -17,24 +12,14 @@ import java.util.Map;
* @param <T2> Type 2
* @param <T3> Type 3
*/
-public class Signal3<T1, T2, T3> {
- private final Map<SignalConnection, Slot3<T1, T2,T3> > binds_ = Collections.synchronizedMap(
- new HashMap<SignalConnection, Slot3<T1, T2,T3> >());
-
+public class Signal3<T1, T2, T3> extends BaseSignal {
/**
* Add a slot which will be notified
* @param bind slot, not null
* @return signal connection
*/
public SignalConnection connect(Slot3<T1, T2,T3> bind) {
- final SignalConnection connection = new SignalConnection();
- binds_.put(connection, bind);
- connection.onDestroyed.connect(new Slot() {
- public void call() {
- binds_.remove(connection);
- }
- });
- return connection;
+ return addBind(bind);
}
/**
@@ -43,18 +28,12 @@ public class Signal3<T1, T2, T3> {
* @param p2 parameter value 2
* @param p3 parameter value 3
*/
- public void emit(T1 p1, T2 p2,T3 p3) {
- List<Slot3<T1,T2, T3>> binds = new ArrayList<Slot3<T1, T2, T3>>();
- binds.addAll(binds_.values());
- for (Slot3<T1, T2, T3> bind : binds) {
- bind.call(p1, p2, p3);
+ @SuppressWarnings("unchecked")
+ public void emit(T1 p1, T2 p2, T3 p3) {
+ final BaseSlot[] binds = getBinds();
+ if (binds == null) {return;}
+ for (BaseSlot bind : binds) {
+ ((Slot3<T1, T2, T3>)bind).call(p1, p2, p3);
}
}
-
- /**
- * Remove all slots(listeners)
- */
- public void disconnectAll() {
- binds_.clear();
- }
}
diff --git a/src/com/isode/stroke/signals/Signal4.java b/src/com/isode/stroke/signals/Signal4.java
index 6a29641..edf30ed 100644
--- a/src/com/isode/stroke/signals/Signal4.java
+++ b/src/com/isode/stroke/signals/Signal4.java
@@ -1,18 +1,10 @@
/*
- * Copyright (c) 2012-2013, Isode Limited, London, England.
+ * Copyright (c) 2012-2015, Isode Limited, London, England.
* All rights reserved.
*/
package com.isode.stroke.signals;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import com.isode.stroke.signals.SignalConnection;
-import com.isode.stroke.signals.Slot;
/**
@@ -22,24 +14,14 @@ import com.isode.stroke.signals.Slot;
* @param <T3> Type 3
* @param <T4> Type 4
*/
-public class Signal4<T1, T2, T3, T4> {
- private final Map<SignalConnection, Slot4<T1, T2, T3, T4> > binds_ = Collections.synchronizedMap(
- new HashMap<SignalConnection, Slot4<T1, T2, T3, T4> >());
-
+public class Signal4<T1, T2, T3, T4> extends BaseSignal {
/**
* Add a slot which will be notified
* @param bind slot, not null
* @return signal connection
*/
public SignalConnection connect(Slot4<T1, T2, T3, T4> bind) {
- final SignalConnection connection = new SignalConnection();
- binds_.put(connection, bind);
- connection.onDestroyed.connect(new Slot() {
- public void call() {
- binds_.remove(connection);
- }
- });
- return connection;
+ return addBind(bind);
}
/**
@@ -49,18 +31,12 @@ public class Signal4<T1, T2, T3, T4> {
* @param p3 parameter value 3
* @param p4 parameter value 4
*/
+ @SuppressWarnings("unchecked")
public void emit(T1 p1, T2 p2, T3 p3, T4 p4) {
- List<Slot4<T1, T2, T3, T4>> binds = new ArrayList<Slot4<T1, T2, T3, T4>>();
- binds.addAll(binds_.values());
- for (Slot4<T1, T2, T3, T4> bind : binds) {
- bind.call(p1, p2, p3, p4);
+ final BaseSlot[] binds = getBinds();
+ if (binds == null) {return;}
+ for (BaseSlot bind : binds) {
+ ((Slot4<T1, T2, T3, T4>)bind).call(p1, p2, p3, p4);
}
}
-
- /**
- * Remove all slots(listeners)
- */
- public void disconnectAll() {
- binds_.clear();
- }
}
diff --git a/src/com/isode/stroke/signals/Signal7.java b/src/com/isode/stroke/signals/Signal7.java
index 296cc02..bbf6559 100644
--- a/src/com/isode/stroke/signals/Signal7.java
+++ b/src/com/isode/stroke/signals/Signal7.java
@@ -5,14 +5,6 @@
package com.isode.stroke.signals;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import com.isode.stroke.signals.SignalConnection;
-import com.isode.stroke.signals.Slot;
/**
@@ -22,24 +14,14 @@ import com.isode.stroke.signals.Slot;
* @param <T3> Type 3
* @param <T4> Type 4
*/
-public class Signal7<T1, T2, T3, T4, T5, T6, T7> {
- private final Map<SignalConnection, Slot7<T1, T2, T3, T4, T5, T6, T7> > binds_ = Collections.synchronizedMap(
- new HashMap<SignalConnection, Slot7<T1, T2, T3, T4, T5, T6, T7> >());
-
+public class Signal7<T1, T2, T3, T4, T5, T6, T7> extends BaseSignal {
/**
* Add a slot which will be notified
* @param bind slot, not null
* @return signal connection
*/
public SignalConnection connect(Slot7<T1, T2, T3, T4, T5, T6, T7> bind) {
- final SignalConnection connection = new SignalConnection();
- binds_.put(connection, bind);
- connection.onDestroyed.connect(new Slot() {
- public void call() {
- binds_.remove(connection);
- }
- });
- return connection;
+ return addBind(bind);
}
/**
@@ -49,18 +31,12 @@ public class Signal7<T1, T2, T3, T4, T5, T6, T7> {
* @param p3 parameter value 3
* @param p4 parameter value 4
*/
+ @SuppressWarnings("unchecked")
public void emit(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7) {
- List<Slot7<T1, T2, T3, T4, T5, T6, T7>> binds = new ArrayList<Slot7<T1, T2, T3, T4, T5, T6, T7>>();
- binds.addAll(binds_.values());
- for (Slot7<T1, T2, T3, T4, T5, T6, T7> bind : binds) {
- bind.call(p1, p2, p3, p4, p5, p6, p7);
+ final BaseSlot[] binds = getBinds();
+ if (binds == null) {return;}
+ for (BaseSlot bind : binds) {
+ ((Slot7<T1, T2, T3, T4, T5, T6, T7>)bind).call(p1, p2, p3, p4, p5, p6, p7);
}
}
-
- /**
- * Remove all slots(listeners)
- */
- public void disconnectAll() {
- binds_.clear();
- }
}
diff --git a/src/com/isode/stroke/signals/SignalConnection.java b/src/com/isode/stroke/signals/SignalConnection.java
index 452c80b..30bbf82 100644
--- a/src/com/isode/stroke/signals/SignalConnection.java
+++ b/src/com/isode/stroke/signals/SignalConnection.java
@@ -1,15 +1,22 @@
/*
- * Copyright (c) 2010, Isode Limited, London, England.
+ * Copyright (c) 2010-2015, Isode Limited, London, England.
* All rights reserved.
*/
package com.isode.stroke.signals;
-
public class SignalConnection {
- public final Signal onDestroyed = new Signal();
-
+ interface DisconnectListener {
+ void onSignalConnectionDisconnect(SignalConnection connection);
+ }
+
+ private final DisconnectListener listener;
+
+ SignalConnection(DisconnectListener listener) {
+ this.listener = listener;
+ }
+
public void disconnect() {
- onDestroyed.emit();
+ listener.onSignalConnectionDisconnect(this);
}
}
diff --git a/src/com/isode/stroke/signals/Slot.java b/src/com/isode/stroke/signals/Slot.java
index 35b8c70..780892d 100644
--- a/src/com/isode/stroke/signals/Slot.java
+++ b/src/com/isode/stroke/signals/Slot.java
@@ -8,6 +8,6 @@ package com.isode.stroke.signals;
/**
* Bind class for connecting to a signal.
*/
-public interface Slot {
+public interface Slot extends BaseSlot {
void call();
}
diff --git a/src/com/isode/stroke/signals/Slot1.java b/src/com/isode/stroke/signals/Slot1.java
index a8f0179..001dca7 100644
--- a/src/com/isode/stroke/signals/Slot1.java
+++ b/src/com/isode/stroke/signals/Slot1.java
@@ -8,6 +8,6 @@ package com.isode.stroke.signals;
/**
* Bind class for connecting to a signal.
*/
-public interface Slot1<T1> {
+public interface Slot1<T1> extends BaseSlot {
void call(T1 p1);
}
diff --git a/src/com/isode/stroke/signals/Slot2.java b/src/com/isode/stroke/signals/Slot2.java
index b3b9330..03eb9a6 100644
--- a/src/com/isode/stroke/signals/Slot2.java
+++ b/src/com/isode/stroke/signals/Slot2.java
@@ -8,6 +8,6 @@ package com.isode.stroke.signals;
/**
* Bind class for connecting to a signal.
*/
-public interface Slot2<T1, T2> {
+public interface Slot2<T1, T2> extends BaseSlot {
void call(T1 p1, T2 p2);
}
diff --git a/src/com/isode/stroke/signals/Slot3.java b/src/com/isode/stroke/signals/Slot3.java
index ee5ccbc..63c371c 100644
--- a/src/com/isode/stroke/signals/Slot3.java
+++ b/src/com/isode/stroke/signals/Slot3.java
@@ -11,7 +11,7 @@ package com.isode.stroke.signals;
* @param <T2> Type 2
* @param <T3> Type 3
*/
-public interface Slot3<T1, T2,T3> {
+public interface Slot3<T1, T2,T3> extends BaseSlot {
/**
* This method will be called on notification from a signal
* @param p1 parameter value 1
diff --git a/src/com/isode/stroke/signals/Slot4.java b/src/com/isode/stroke/signals/Slot4.java
index 02e6fd9..93401db 100644
--- a/src/com/isode/stroke/signals/Slot4.java
+++ b/src/com/isode/stroke/signals/Slot4.java
@@ -12,7 +12,7 @@ package com.isode.stroke.signals;
* @param <T3> Type 3
* @param <T4> Type 4
*/
-public interface Slot4<T1, T2, T3, T4> {
+public interface Slot4<T1, T2, T3, T4> extends BaseSlot {
/**
* This method will be called on notification from a signal
* @param p1 parameter value 1
diff --git a/src/com/isode/stroke/signals/Slot7.java b/src/com/isode/stroke/signals/Slot7.java
index 7df6973..752d9a8 100644
--- a/src/com/isode/stroke/signals/Slot7.java
+++ b/src/com/isode/stroke/signals/Slot7.java
@@ -15,7 +15,7 @@ package com.isode.stroke.signals;
* @param <T6> Type 6
* @param <T7> Type 7
*/
-public interface Slot7<T1, T2, T3, T4, T5, T6, T7> {
+public interface Slot7<T1, T2, T3, T4, T5, T6, T7> extends BaseSlot {
/**
* This method will be called on notification from a signal
* @param p1 parameter value 1