Bug 576333 - optimize EclipseContext.localValueComputations

Use a ConcurrentHashmap because its faster and has atomic operations.
It is not a big hotspot though.

also fixed typo "dipose"->"dispose"

Change-Id: Ib1ca93f1a7cd74ab4c5391220f451a78c72497d3
Signed-off-by: Joerg Kubitz <jkubitz-eclipse@gmx.de>
Reviewed-on: https://git.eclipse.org/r/c/platform/eclipse.platform.runtime/+/185956
Tested-by: Platform Bot <platform-bot@eclipse.org>
diff --git a/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/ContextChangeEvent.java b/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/ContextChangeEvent.java
index 39fbad1..400abe0 100644
--- a/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/ContextChangeEvent.java
+++ b/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/ContextChangeEvent.java
@@ -77,12 +77,12 @@
 	 */
 	public static final int RECALC = 6;
 
-	private Object[] args;
-	private IEclipseContext context;
-	private int eventType;
-	private String key;
+	private final Object[] args;
+	private final IEclipseContext context;
+	private final int eventType;
+	private final String key;
 
-	private Object oldValue;
+	private final Object oldValue;
 
 	/**
 	 * Creates a new context event.
diff --git a/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/EclipseContext.java b/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/EclipseContext.java
index 6b92681..a83bdb4 100644
--- a/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/EclipseContext.java
+++ b/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/EclipseContext.java
@@ -29,6 +29,7 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.Stack;
+import java.util.concurrent.ConcurrentHashMap;
 import org.eclipse.e4.core.contexts.IContextFunction;
 import org.eclipse.e4.core.contexts.IEclipseContext;
 import org.eclipse.e4.core.contexts.RunAndTrack;
@@ -90,7 +91,7 @@
 	}
 
 	private WeakGroupedListenerList weakListeners = new WeakGroupedListenerList();
-	private Map<String, ValueComputation> localValueComputations = Collections.synchronizedMap(new HashMap<>());
+	private Map<String, ValueComputation> localValueComputations = new ConcurrentHashMap<>();
 
 	final protected ConcurrentNeutralValueMap<String, Object> localValues = // null values allowed
 			new ConcurrentNeutralValueMap<>(ConcurrentNeutralValueMap.neutralObject());
@@ -195,11 +196,10 @@
 			}
 			notifyOnDisposal.clear();
 		}
-
-		for (ValueComputation computation : localValueComputations.values()) {
-			computation.dipose();
-		}
-		localValueComputations.clear();
+		localValueComputations.values().removeIf(computation -> {
+			computation.dispose();
+			return true;
+		});
 
 		// if this was the parent's active child, deactivate it
 		EclipseContext parent = getParent();
@@ -293,21 +293,20 @@
 	 * computations and listeners that depend on this name.
 	 */
 	public void invalidate(String name, int eventType, Object oldValue, Object newValue, Set<Scheduled> scheduled) {
-		ContextChangeEvent event = null;
-		ValueComputation computation = localValueComputations.get(name);
-		if (computation != null) {
-			event = new ContextChangeEvent(this, eventType, null, name, oldValue);
+		ContextChangeEvent event = new ContextChangeEvent(this, eventType, null, name, oldValue);
+
+		ValueComputation newComputation = localValueComputations.computeIfPresent(name, (k, computation) -> {
 			if (computation.shouldRemove(event)) {
-				localValueComputations.remove(name);
 				weakListeners.remove(computation);
+				return null; // remove
 			}
-			computation.handleInvalid(event, scheduled);
+			return computation; // keep
+		});
+		if (newComputation != null) {
+			newComputation.handleInvalid(event, scheduled);
 		}
 		Set<Computation> namedComputations = weakListeners.getListeners(name);
 		if (namedComputations != null && !namedComputations.isEmpty()) {
-			if (event == null) {
-				event = new ContextChangeEvent(this, eventType, null, name, oldValue);
-			}
 			for (Computation listener : namedComputations) {
 				listener.handleInvalid(event, scheduled);
 			}
@@ -522,11 +521,11 @@
 
 	protected void invalidateLocalComputations(Set<Scheduled> scheduled) {
 		ContextChangeEvent event = new ContextChangeEvent(this, ContextChangeEvent.ADDED, null, null, null);
-		for (Computation computation : localValueComputations.values()) {
+		localValueComputations.values().removeIf(computation -> {
 			weakListeners.remove(computation);
 			computation.handleInvalid(event, scheduled);
-		}
-		localValueComputations.clear();
+			return true;
+		});
 
 		// We need to cleanup computations recursively see bug 468048
 		for (EclipseContext c : getChildren()) {
diff --git a/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/ValueComputation.java b/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/ValueComputation.java
index 9e51e96..9b3c600 100644
--- a/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/ValueComputation.java
+++ b/bundles/org.eclipse.e4.core.contexts/src/org/eclipse/e4/core/internal/contexts/ValueComputation.java
@@ -116,7 +116,7 @@
 		return valid;
 	}
 
-	public void dipose() {
+	public void dispose() {
 		valid = false;
 	}
 }
\ No newline at end of file