Author: ehillenius
Date: Mon Feb 12 12:18:29 2007
New Revision: 506617
URL: http://svn.apache.org/viewvc?view=rev&rev=506617
Log:
use identity table rather than object hasCode based
Modified:
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/util/io/SerializableChecker.java
Modified:
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/util/io/SerializableChecker.java
URL:
http://svn.apache.org/viewvc/incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/util/io/SerializableChecker.java?view=diff&rev=506617&r1=506616&r2=506617
==============================================================================
---
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/util/io/SerializableChecker.java
(original)
+++
incubator/wicket/branches/wicket-1.x/wicket/src/main/java/wicket/util/io/SerializableChecker.java
Mon Feb 12 12:18:29 2007
@@ -29,9 +29,9 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
+import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
@@ -79,6 +79,134 @@
}
/**
+ * Lightweight identity hash table which maps objects to integer
handles,
+ * assigned in ascending order (comes from [EMAIL PROTECTED]
ObjectOutputStream}).
+ */
+ private static final class HandleTable
+ {
+ /* number of mappings in table/next available handle */
+ private int size;
+ /* size threshold determining when to expand hash spine */
+ private int threshold;
+ /* factor for computing size threshold */
+ private final float loadFactor;
+ /* maps hash value -> candidate handle value */
+ private int[] spine;
+ /* maps handle value -> next candidate handle value */
+ private int[] next;
+ /* maps handle value -> associated object */
+ private Object[] objs;
+
+ HandleTable(int initialCapacity, float loadFactor)
+ {
+ this.loadFactor = loadFactor;
+ spine = new int[initialCapacity];
+ next = new int[initialCapacity];
+ objs = new Object[initialCapacity];
+ threshold = (int)(initialCapacity * loadFactor);
+ clear();
+ }
+
+ private void growEntries()
+ {
+ int newLength = (next.length << 1) + 1;
+ int[] newNext = new int[newLength];
+ System.arraycopy(next, 0, newNext, 0, size);
+ next = newNext;
+
+ Object[] newObjs = new Object[newLength];
+ System.arraycopy(objs, 0, newObjs, 0, size);
+ objs = newObjs;
+ }
+
+ private void growSpine()
+ {
+ spine = new int[(spine.length << 1) + 1];
+ threshold = (int)(spine.length * loadFactor);
+ Arrays.fill(spine, -1);
+ for (int i = 0; i < size; i++)
+ {
+ insert(objs[i], i);
+ }
+ }
+
+ private int hash(Object obj)
+ {
+ return System.identityHashCode(obj) & 0x7FFFFFFF;
+ }
+
+ private void insert(Object obj, int handle)
+ {
+ int index = hash(obj) % spine.length;
+ objs[handle] = obj;
+ next[handle] = spine[index];
+ spine[index] = handle;
+ }
+
+ /**
+ * Assigns next available handle to given object, and returns
handle
+ * value. Handles are assigned in ascending order starting at 0.
+ *
+ * @param obj
+ * @return
+ */
+ int assign(Object obj)
+ {
+ if (size >= next.length)
+ {
+ growEntries();
+ }
+ if (size >= threshold)
+ {
+ growSpine();
+ }
+ insert(obj, size);
+ return size++;
+ }
+
+ void clear()
+ {
+ Arrays.fill(spine, -1);
+ Arrays.fill(objs, 0, size, null);
+ size = 0;
+ }
+
+ boolean contains(Object obj)
+ {
+ return lookup(obj) != -1;
+ }
+
+ /**
+ * Looks up and returns handle associated with given object, or
-1 if no
+ * mapping found.
+ *
+ * @param obj
+ * @return
+ */
+ int lookup(Object obj)
+ {
+ if (size == 0)
+ {
+ return -1;
+ }
+ int index = hash(obj) % spine.length;
+ for (int i = spine[index]; i >= 0; i = next[i])
+ {
+ if (objs[i] == obj)
+ {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ int size()
+ {
+ return size;
+ }
+ }
+
+ /**
* Does absolutely nothing.
*/
private static class NoopOutputStream extends OutputStream
@@ -270,7 +398,7 @@
private final LinkedList traceStack = new LinkedList();
/** set for checking circular references. */
- private final HashSet checked = new HashSet();
+ private final HandleTable checked = new HandleTable(10, (float)3.00);
/** string stack with current names pushed. */
private LinkedList nameStack = new LinkedList();
@@ -355,7 +483,7 @@
}
else if (cls.isArray())
{
- checked.add(obj);
+ checked.assign(obj);
Class ccl = cls.getComponentType();
if (!(ccl.isPrimitive()))
{
@@ -380,22 +508,13 @@
public void writeObject(Object
streamObj) throws IOException
{
- try
- {
- // Check for circular
reference.
- if
(checked.contains(streamObj))
- {
- return;
- }
- }
- catch (Exception e)
+ // Check for circular reference.
+ if (checked.contains(streamObj))
{
- log.warn("error
invoking hashCode: " + e.getMessage() + ", path:"
- +
currentPath() + ": ");
return;
}
- checked.add(streamObj);
+ checked.assign(streamObj);
String arrayPos = "[write:" +
count++ + "]";
simpleName = arrayPos;
fieldDescription += arrayPos;
@@ -464,22 +583,13 @@
}
counter++;
- try
- {
- // Check for circular
reference.
- if
(checked.contains(streamObj))
- {
- return null;
- }
- }
- catch (Exception e)
+ // Check for circular reference.
+ if (checked.contains(streamObj))
{
- log.warn("error
invoking hashCode: " + e.getMessage() + ", path:"
- +
currentPath() + ": ");
return null;
}
- checked.add(obj);
+ checked.assign(obj);
String arrayPos = "[write:" +
counter + "]";
simpleName = arrayPos;
fieldDescription += arrayPos;
@@ -526,7 +636,7 @@
{
throw new RuntimeException(e);
}
- checked.add(obj);
+ checked.assign(obj);
checkFields(obj, slotDesc);
}
}
@@ -580,18 +690,9 @@
continue;
}
- try
- {
- // Check for circular reference.
- if (checked.contains(objVals[i]))
- {
- continue;
- }
- }
- catch (Exception e)
+ // Check for circular reference.
+ if (checked.contains(objVals[i]))
{
- log.warn("error invoking hashCode: " +
e.getMessage() + ", path:"
- + currentPath() + ": ");
continue;
}