Author: [EMAIL PROTECTED]
Date: Thu Nov 13 20:22:40 2008
New Revision: 4072
Modified:
branches/1_6_clean_events/user/src/com/google/gwt/event/shared/HandlerManager.java
Log:
As initial benchmarks are leaning towards the desire to include the more
complicated handler registry, it seems reasonably safe to add it back in.
Modified:
branches/1_6_clean_events/user/src/com/google/gwt/event/shared/HandlerManager.java
==============================================================================
---
branches/1_6_clean_events/user/src/com/google/gwt/event/shared/HandlerManager.java
(original)
+++
branches/1_6_clean_events/user/src/com/google/gwt/event/shared/HandlerManager.java
Thu Nov 13 20:22:40 2008
@@ -15,6 +15,8 @@
*/
package com.google.gwt.event.shared;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.event.shared.GwtEvent.Type;
import com.google.gwt.user.client.Command;
@@ -81,10 +83,182 @@
}
}
+ /**
+ * Default JavaScript handler registry. This is in the shared class but
should
+ * never be called outside of a GWT runtime environment.
+ *
+ * The JsHandlerRegistry makes use of the fact that in the large
majority of
+ * cases, only one or two handlers are added for each event type.
Therefore,
+ * rather than storing handlers in a list of lists, we store then in a
single
+ * flattened array with an escape clause to handle the rare case where
we have
+ * more handlers then expected.
+ */
+ private static class JsHandlerRegistry extends JavaScriptObject {
+
+ /**
+ * Required constructor.
+ */
+ protected JsHandlerRegistry() {
+ }
+
+ public final <H extends EventHandler> void addHandler(
+ Type<H> type, H myHandler) {
+
+ // The base is the equivalent to a c pointer into the flattened
handler
+ // data structure.
+ int base = type.hashCode();
+ int count = getCount(base);
+ boolean flattened = isFlattened(base);
+ H handler = myHandler;
+ // If we already have the maximum number of handlers we can store in
the
+ // flattened data structure, store the handlers in an external list
+ // instead.
+ if ((count == EXPECTED_HANDLERS) & flattened) {
+ unflatten(base);
+ flattened = false;
+ }
+ if (flattened) {
+ setFlatHandler(base, count, handler);
+ } else {
+ setHandler(base, count, handler);
+ }
+ setCount(base, count + 1);
+ }
+
+ public final <H extends EventHandler> void fireEvent(GwtEvent<H>
event) {
+ Type<H> type = event.getAssociatedType();
+ int base = type.hashCode();
+ int count = getCount(base);
+ boolean isFlattened = isFlattened(base);
+ if (isFlattened) {
+ for (int i = 0; i < count; i++) {
+ // Gets the given handler to fire.
+ H handler = getFlatHandler(base, i);
+ // Fires the handler.
+ event.dispatch(handler);
+ }
+ } else {
+ JavaScriptObject handlers = getHandlers(base);
+ for (int i = 0; i < count; i++) {
+ // Gets the given handler to fire.
+
+ H handler = getHandler(handlers, i);
+
+ // Fires the handler.
+ event.dispatch(handler);
+ }
+ }
+ }
+
+ public final <H extends EventHandler> H getHandler(GwtEvent.Type<H>
type,
+ int index) {
+ int base = type.hashCode();
+ int count = getCount(base);
+ if (index >= count) {
+ throw new IndexOutOfBoundsException("index: " + index);
+ }
+ return getHandler(base, index, isFlattened(base));
+ }
+
+ public final int getHandlerCount(GwtEvent.Type<?> eventKey) {
+ return getCount(eventKey.hashCode());
+ }
+
+ public final <H> void removeHandler(GwtEvent.Type<H> eventKey,
+ EventHandler handler) {
+ int base = eventKey.hashCode();
+
+ // Removing a handler is unusual, so smaller code is preferable to
+ // handling both flat and dangling list of pointers.
+ if (isFlattened(base)) {
+ unflatten(base);
+ }
+ boolean result = removeHelper(base, handler);
+ // Hiding this behind an assertion as we'd rather not force the
compiler
+ // to have to include all handler.toString() instances.
+ assert result : handler + " did not exist";
+ }
+
+ private native int getCount(int index) /*-{
+ var count = this[index];
+ return count == null? 0:count;
+ }-*/;
+
+ private native <H extends EventHandler> H getFlatHandler(int base, int
index) /*-{
+ return this[base + 2 + index];
+ }-*/;
+
+ private native <H extends EventHandler> H getHandler(int base, int
index,
+ boolean flattened) /*-{
+ return flattened? this[base + 2 + index]: this[base + 1][index];
+ }-*/;
+
+ private native <H extends EventHandler> H getHandler(
+ JavaScriptObject handlers, int index) /*-{
+ return handlers[index];
+ }-*/;
+
+ private native JavaScriptObject getHandlers(int base) /*-{
+ return this[base + 1];
+ }-*/;
+
+ private native boolean isFlattened(int base) /*-{
+ return this[base + 1] == null;
+ }-*/;
+
+ private native boolean removeHelper(int base, EventHandler handler)
/*-{
+ // Find the handler.
+ var count = this[base];
+ var handlerList = this[base + 1];
+ var handlerIndex = -1;
+ for(var index = 0; index < count; index++){
+ if(handlerList[index] == handler){
+ handlerIndex = index;
+ break;
+ }
+ }
+ if(handlerIndex == -1) {
+ return false;
+ }
+
+ // Remove the handler.
+ var last = count -1;
+ for(; handlerIndex < last; handlerIndex++){
+ handlerList[handlerIndex] = handlerList[handlerIndex+1]
+ }
+ handlerList[last] = null;
+ this[base] = this[base]-1;
+ return true;
+ }-*/;
+
+ private native void setCount(int index, int count) /*-{
+ this[index] = count;
+ }-*/;
+
+ private native void setFlatHandler(int base, int index, EventHandler
handler) /*-{
+ this[base + 2 + index] = handler;
+ }-*/;
+
+ private native void setHandler(int base, int index, EventHandler
handler) /*-{
+ this[base + 1][index] = handler;
+ }-*/;
+
+ private native void unflatten(int base) /*-{
+ var handlerList = {};
+ var count = this[base];
+ var start = base + 2;
+ for(var i = 0; i < count;i++){
+ handlerList[i] = this[start + i];
+ this[start + i] = null;
+ }
+ this[base + 1] = handlerList;
+ }-*/;
+ }
+
// Used to optimize the JavaScript handler container structure.
private static int EXPECTED_HANDLERS = 5;
- private static final boolean useJs = false;
+ private static final boolean useJs = GWT.isClient();
private static int index;
@@ -98,10 +272,9 @@
}
private int firingDepth = 0;
- // Only JavaHandlerRegistry is supported for now as we need to decide if
we
- // need the more complicated js structure or not.
+ // Only one of JsHandlerRegistry and JavaHandlerRegistry are live at
once.
+ private JsHandlerRegistry javaScriptRegistry;
private JavaHandlerRegistry javaRegistry;
- private JavaHandlerRegistry javaScriptRegistry;
// source of the event.
private final Object source;
@@ -116,7 +289,7 @@
*/
public HandlerManager(Object source) {
if (useJs) {
- javaScriptRegistry = null;
+ javaScriptRegistry = JavaScriptObject.createObject().cast();
} else {
javaRegistry = new JavaHandlerRegistry();
}
--~--~---------~--~----~------------~-------~--~----~
http://groups.google.com/group/Google-Web-Toolkit-Contributors
-~----------~----~----~----~------~----~------~--~---