[jboss-svn-commits] JBL Code SVN: r6288 - in labs/jbossrules/trunk/drools-core/src: main/java/org/drools/util test/java/org/drools/util

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Mon Sep 18 18:20:32 EDT 2006


Author: mark.proctor at jboss.com
Date: 2006-09-18 18:20:26 -0400 (Mon, 18 Sep 2006)
New Revision: 6288

Added:
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/AbstractHashTable.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/FieldIndexHashTable.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/ObjectHashMap.java
   labs/jbossrules/trunk/drools-core/src/test/java/org/drools/util/FieldIndexHashTableTest.java
   labs/jbossrules/trunk/drools-core/src/test/java/org/drools/util/ObjectHashMapTest.java
Removed:
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/DroolsMap.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/FieldIndexEntry.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/FieldIndexMap.java
   labs/jbossrules/trunk/drools-core/src/test/java/org/drools/util/FieldIndexMapTest.java
Modified:
   labs/jbossrules/trunk/drools-core/src/test/java/org/drools/util/FieldIndexEntryTest.java
Log:


Added: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/AbstractHashTable.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/AbstractHashTable.java	2006-09-18 20:30:21 UTC (rev 6287)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/AbstractHashTable.java	2006-09-18 22:20:26 UTC (rev 6288)
@@ -0,0 +1,188 @@
+/**
+ * 
+ */
+package org.drools.util;
+
+import java.io.Serializable;
+
+public abstract class AbstractHashTable implements Serializable {	
+    static final int  MAX_CAPACITY = 1 << 30;
+
+    protected int     size;
+    protected int     threshold;
+    protected float   loadFactor;    
+
+    protected boolean checkExists;
+    protected ObjectComparator comparator;
+    
+    protected Entry[] table;
+
+    public AbstractHashTable() {
+        this( 16,
+              0.75f );
+    }
+
+    public AbstractHashTable(int capacity,
+                     float loadFactor) {
+        this.loadFactor = loadFactor;
+        this.threshold = (int) (capacity * loadFactor);
+        this.table = new Entry[capacity];
+        this.comparator = EqualityEquals.getInstance();
+        this.checkExists = false;
+    }
+
+    
+	public void setCheckExists(boolean checkExists) {
+		this.checkExists = checkExists;
+	}
+
+	public void setComparator(ObjectComparator comparator) {
+		this.comparator = comparator;
+	}    
+    
+    protected void resize(int newCapacity) {
+        Entry[] oldTable = this.table;
+        int oldCapacity = oldTable.length;
+        if ( oldCapacity == MAX_CAPACITY ) {
+            this.threshold = Integer.MAX_VALUE;
+            return;
+        }
+
+        Entry[] newTable = new Entry[newCapacity];
+
+        for ( int i = 0; i < this.table.length; i++ ) {
+            Entry entry = this.table[i];
+            if ( entry == null ) {
+                continue;
+            }
+            this.table[i] = null;
+            Entry next = null;
+            while ( entry != null ) {
+                next = entry.getNext();
+
+                int index = indexOf( entry.hashCode(), newTable.length  );
+                entry.setNext( newTable[index] );
+                newTable[index] = entry;
+
+                entry = next;
+            }
+        }
+
+        this.table = newTable;
+        this.threshold = (int) (newCapacity * this.loadFactor);
+    }
+
+//    public void add(Entry entry) {
+//        int index = indexOf( entry.hashCode(), table.length  );
+//
+//        
+//        boolean exists = false;
+//        
+//        // scan the linked entries to see if it exists
+//        if ( !checkExists ) {
+//            Entry current = this.table[index];
+//            int hashCode = entry.hashCode();
+//            while ( current != null ) {                
+//                if  ( hashCode == current.hashCode() && entry.equals( current ) ) {
+//                    exists = true;
+//                }
+//            }                        
+//        }
+//        
+//        if( exists == false ) {
+//            entry.setNext( this.table[index] );
+//            this.table[index] = entry;
+//    
+//            if ( this.size++ >= this.threshold ) {
+//                resize( 2 * this.table.length );
+//            }
+//        }
+//
+//    }
+//
+//    public Entry get(Entry entry) {
+//        int index = indexOf( entry.hashCode(), table.length  );
+//        Entry current = this.table[index];
+//        while ( current != null ) {
+//            if ( entry.hashCode() == current.hashCode() && entry.equals( current ) ) {
+//                return current;
+//            }
+//            current = current.getNext();
+//        }
+//        return null;
+//    }
+//
+//    public Entry remove(Entry entry) {
+//        int index = indexOf( entry.hashCode(), table.length  );
+//        Entry previous = this.table[index];        
+//        Entry current = previous;
+//        int hashCode = entry.hashCode();
+//        while ( current != null ) {
+//            Entry next = current.getNext();
+//            if ( hashCode == current.hashCode() && entry.equals( current ) ) {
+//                if( previous  == current ) {
+//                    this.table[index] = next;
+//                    previous.setNext( next );
+//                }
+//                current.setNext( null );
+//                this.size--;
+//                return current;
+//            }
+//            previous = current;
+//            current = next;
+//        }
+//        return current;
+//    }
+
+    public Entry getBucket(int hashCode) {
+        return this.table[ indexOf( hashCode, table.length ) ];
+    }
+
+    public int size() {
+        return this.size;
+    }
+    
+    protected int indexOf(int hashCode, int dataSize) {
+        int index = hashCode % dataSize;
+        if ( index < 0 ) {
+            index  = index * -1;
+        }
+        return index;
+    }
+    
+    public interface ObjectComparator {
+    	public boolean equal(Object object1, Object object2);
+    }
+    
+    public static class InstanceEquals implements ObjectComparator {
+    	public static ObjectComparator INSTANCE =  new InstanceEquals();
+    	
+    	public static ObjectComparator getInstance() {
+    		return INSTANCE;
+    	}
+    	
+    	private InstanceEquals() {
+    		
+    	}
+    	
+		public boolean equal(Object object1, Object object2) {
+			return object1 == object2;
+		}    	
+    }
+    
+    public static class EqualityEquals implements ObjectComparator {
+    	public static ObjectComparator INSTANCE =  new EqualityEquals();
+    	
+    	public static ObjectComparator getInstance() {
+    		return INSTANCE;
+    	}
+    	
+    	private EqualityEquals() {
+    		
+    	}    	
+    	
+		public boolean equal(Object object1, Object object2) {
+			return object1.equals( object2 );
+		}    	
+    }         
+}
\ No newline at end of file

Deleted: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/DroolsMap.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/DroolsMap.java	2006-09-18 20:30:21 UTC (rev 6287)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/DroolsMap.java	2006-09-18 22:20:26 UTC (rev 6288)
@@ -1,139 +0,0 @@
-/**
- * 
- */
-package org.drools.util;
-
-public class DroolsMap {
-    static final int  MAX_CAPACITY = 1 << 30;
-
-    protected int     size;
-    protected int     threshold;
-    protected float   loadFactor;
-    
-    protected boolean checkExists;
-
-    protected Entry[] table;
-
-    public DroolsMap() {
-        this( 16,
-              0.75f );
-    }
-
-    public DroolsMap(int capacity,
-                     float loadFactor) {
-        this.loadFactor = loadFactor;
-        this.threshold = (int) (capacity * loadFactor);
-        this.table = new Entry[capacity];
-    }
-
-    protected void resize(int newCapacity) {
-        Entry[] oldTable = this.table;
-        int oldCapacity = oldTable.length;
-        if ( oldCapacity == MAX_CAPACITY ) {
-            this.threshold = Integer.MAX_VALUE;
-            return;
-        }
-
-        Entry[] newTable = new Entry[newCapacity];
-
-        for ( int i = 0; i < this.table.length; i++ ) {
-            Entry entry = this.table[i];
-            if ( entry == null ) {
-                continue;
-            }
-            this.table[i] = null;
-            Entry next = null;
-            while ( entry != null ) {
-                next = entry.getNext();
-
-                int index = indexOf( entry.hashCode(), newTable.length  );
-                entry.setNext( newTable[index] );
-                newTable[index] = entry;
-
-                entry = next;
-            }
-        }
-
-        this.table = newTable;
-        this.threshold = (int) (newCapacity * this.loadFactor);
-    }
-
-    public void add(Entry entry) {
-        int index = indexOf( entry.hashCode(), table.length  );
-
-        
-        boolean exists = false;
-        
-        // scan the linked entries to see if it exists
-        if ( !checkExists ) {
-            Entry current = this.table[index];
-            int hashCode = entry.hashCode();
-            while ( current != null ) {                
-                if  ( hashCode == current.hashCode() && entry.equals( current ) ) {
-                    exists = true;
-                }
-            }                        
-        }
-        
-        if( exists == false ) {
-            entry.setNext( this.table[index] );
-            this.table[index] = entry;
-    
-            if ( this.size++ >= this.threshold ) {
-                resize( 2 * this.table.length );
-            }
-        }
-
-    }
-
-    public Entry get(Entry entry) {
-        int index = indexOf( entry.hashCode(), table.length  );
-        Entry current = this.table[index];
-        while ( current != null ) {
-            if ( entry.hashCode() == current.hashCode() && entry.equals( current ) ) {
-                return current;
-            }
-            current = current.getNext();
-        }
-        return null;
-    }
-
-    public Entry remove(Entry entry) {
-        int index = indexOf( entry.hashCode(), table.length  );
-        Entry previous = this.table[index];        
-        Entry current = previous;
-        int hashCode = entry.hashCode();
-        while ( current != null ) {
-            Entry next = current.getNext();
-            if ( hashCode == current.hashCode() && entry.equals( current ) ) {
-                if( previous  == current ) {
-                    this.table[index] = next;
-                    previous.setNext( next );
-                }
-                current.setNext( null );
-                this.size--;
-                return current;
-            }
-            previous = current;
-            current = next;
-        }
-        return current;
-    }
-
-    public Entry getBucket(int hashCode) {
-        int index = indexOf( hashCode, table.length );
-        return this.table[index];
-    }
-
-    public int size() {
-        return this.size;
-    }
-    
-    protected int indexOf(int hashCode, int length) {
-        int index = hashCode % length;
-        if ( index < 0 ) {
-            index  = index * -1;
-        }
-        return index;
-    }
-}
\ No newline at end of file

Deleted: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/FieldIndexEntry.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/FieldIndexEntry.java	2006-09-18 20:30:21 UTC (rev 6287)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/FieldIndexEntry.java	2006-09-18 22:20:26 UTC (rev 6288)
@@ -1,88 +0,0 @@
-/**
- * 
- */
-package org.drools.util;
-
-import org.drools.common.InternalFactHandle;
-import org.drools.spi.FieldExtractor;
-
-public class FieldIndexEntry extends BaseEntry {
-    FactEntry            first;
-
-    private final int            hashCode;
-    final int            fieldIndex;
-    private final FieldExtractor extractor;
-
-    public FieldIndexEntry(FieldExtractor extractor,
-                          int fieldIndex,
-                          int hashCode) {
-        this.extractor = extractor;
-        this.fieldIndex = fieldIndex;
-        this.hashCode = hashCode;
-    }
-    
-    public FactEntry getFirst() {
-        return this.first;
-    }
-
-    public void add(InternalFactHandle handle) {
-        FactEntry entry = new FactEntry( handle );            
-        entry.setNext( this.first );
-        this.first = entry;
-    }
-
-    public FactEntry get(InternalFactHandle handle) {
-        long id = handle.getId();
-        FactEntry current = first;
-        while ( current != null ) {
-            if ( current.getFactHandle().getId() == id ) {
-                return current;
-            }
-            current = ( FactEntry ) current.getNext();
-        }
-        return null;
-    }
-
-    public FactEntry remove(InternalFactHandle handle) {
-        long id = handle.getId();
-        
-        FactEntry previous = this.first; 
-        FactEntry current = previous;
-        while ( current != null ) {
-            FactEntry next = ( FactEntry ) current.getNext();
-            if ( current.getFactHandle().getId() == id ) {
-                this.first = next;
-                previous.setNext( next );
-                current.setNext( null );
-                return current;
-            }
-            previous = current;
-            current = next;
-        }
-        return current;
-    }
-
-    public String toString() {
-        return this.extractor.toString();
-    }
-
-    public int fieldIndex() {
-        return this.fieldIndex;
-    }
-
-    public Object getValue() {
-        if ( this.first == null ) {
-            return null;
-        }
-        return this.extractor.getValue( this.first.getFactHandle().getObject() );
-    }
-
-    public int hashCode() {
-        return this.hashCode;
-    }
-
-    public boolean equals(Object object) {
-        FieldIndexEntry other = ( FieldIndexEntry ) object;
-        return this.hashCode == other.hashCode && this.fieldIndex == other.fieldIndex;
-    }
-}
\ No newline at end of file

Copied: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/FieldIndexHashTable.java (from rev 6269, labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/FieldIndexMap.java)
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/FieldIndexMap.java	2006-09-18 13:40:02 UTC (rev 6269)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/FieldIndexHashTable.java	2006-09-18 22:20:26 UTC (rev 6288)
@@ -0,0 +1,213 @@
+/**
+ * 
+ */
+package org.drools.util;
+
+import org.drools.common.InternalFactHandle;
+import org.drools.spi.FieldExtractor;
+
+public class FieldIndexHashTable extends AbstractHashTable {
+    private int            fieldIndex;
+    private FieldExtractor extractor;
+
+    private final int      PRIME = 31;
+
+    private final int      startResult;
+
+    public FieldIndexHashTable(int fieldIndex,
+                         FieldExtractor extractor) {
+        this( 16,
+              0.75f,
+              fieldIndex,
+              extractor );
+    }
+
+    public FieldIndexHashTable(int capacity,
+                         float loadFactor,
+                         int fieldIndex,
+                         FieldExtractor extractor) {
+        super( capacity,
+               loadFactor );
+        this.fieldIndex = fieldIndex;
+        this.extractor = extractor;
+
+        this.startResult = PRIME + this.fieldIndex;
+    }
+
+    public void add(InternalFactHandle handle) {
+        FieldIndexEntry entry = getOrCreate( this.extractor.getValue( handle.getObject() ) );
+        entry.add( handle );
+    }
+
+    public void remove(InternalFactHandle handle) {
+        Object value = this.extractor.getValue( handle.getObject() );
+        int hashCode = PRIME * startResult + ((value == null) ? 0 : value.hashCode());
+
+        int index = indexOf( hashCode, table.length  );
+        
+        // search the table for  the Entry, we need to track previous  and next, so if the 
+        // Entry is empty after  its had the FactEntry removed, we must remove  it from the table
+        FieldIndexEntry previous = ( FieldIndexEntry ) this.table[index];        
+        FieldIndexEntry current = previous;
+        while ( current != null ) {
+            FieldIndexEntry next = ( FieldIndexEntry ) current.next;
+            if ( hashCode == current.hashCode && value.equals( current.getValue() ) ) {
+                current.remove( handle );
+                // If the FactEntryIndex is empty, then remove it from the hash map
+                if (  current.first ==  null  ) {
+                    if( previous  == current ) {
+                        this.table[index] = next;
+                        previous.next = next;
+                    }
+                    current.next = null;
+                    this.size--;
+                }
+                return;
+            }
+            previous = current;
+            current = next;
+        }
+    }   
+
+    public FieldIndexEntry get(Object value) {
+        int hashCode = PRIME * startResult + ((value == null) ? 0 : value.hashCode());
+
+        int index = indexOf( hashCode, table.length  );
+        FieldIndexEntry entry = (FieldIndexEntry) this.table[index];
+
+        while ( entry != null ) {
+            if ( hashCode == entry.hashCode && value.equals( entry.getValue() ) ) {
+                return entry;
+            }
+            entry = (FieldIndexEntry) entry.getNext();
+        }
+        
+        return entry;
+    }
+    
+
+    /**
+     * We use this method to aviod to table lookups for the same hashcode; which is what we would have to do if we did
+     * a get and then a create if the value is null.
+     * 
+     * @param value
+     * @return
+     */
+    public FieldIndexEntry getOrCreate(Object value) {
+        int hashCode = PRIME * startResult + ((value == null) ? 0 : value.hashCode());
+        int index = indexOf( hashCode, table.length  );
+        FieldIndexEntry entry = (FieldIndexEntry) this.table[index];
+
+        while ( entry != null ) {
+            if ( hashCode == entry.hashCode && value.equals( entry.getValue() ) ) {
+                return entry;
+            }
+            entry = (FieldIndexEntry) entry.next;
+        }        
+
+        if ( entry == null ) {
+            entry = new FieldIndexEntry( this.extractor,
+                                         fieldIndex,
+                                         hashCode );
+            entry.next = this.table[index];
+            this.table[index] = entry;
+
+            if ( this.size++ >= this.threshold ) {
+                resize( 2 * this.table.length );
+            }
+        }
+        return entry;
+    }
+    
+    public static class FieldIndexEntry implements Entry {
+        private Entry                next;
+        FactEntry                    first;
+        private final int            hashCode;
+        private final int            fieldIndex;
+        private final FieldExtractor extractor;
+
+        public FieldIndexEntry(FieldExtractor extractor,
+                               int fieldIndex,
+                               int hashCode) {
+            this.extractor = extractor;
+            this.fieldIndex = fieldIndex;
+            this.hashCode = hashCode;
+        }       
+        
+        public Entry getNext() {
+            return next;
+        }
+
+        public void setNext(Entry next) {
+            this.next = next;
+        }
+
+        public FactEntry getFirst() {
+            return this.first;
+        }
+
+        public void add(InternalFactHandle handle) {
+            FactEntry entry = new FactEntry( handle );
+            entry.setNext( this.first );
+            this.first = entry;
+        }
+
+        public FactEntry get(InternalFactHandle handle) {
+            long id = handle.getId();
+            FactEntry current = first;
+            while ( current != null ) {
+                if ( current.getFactHandle().getId() == id ) {
+                    return current;
+                }
+                current = (FactEntry) current.getNext();
+            }
+            return null;
+        }
+
+        public FactEntry remove(InternalFactHandle handle) {
+            long id = handle.getId();
+
+            FactEntry previous = this.first;
+            FactEntry current = previous;
+            while ( current != null ) {
+                FactEntry next = (FactEntry) current.getNext();
+                if ( current.getFactHandle().getId() == id ) {
+                    if ( this.first == current ) {
+                        this.first = next;
+                    } else {
+                        previous.setNext( next );
+                    }
+                    current.setNext( null );
+                    return current;
+                }
+                previous = current;
+                current = next;
+            }
+            return current;
+        }
+
+        public String toString() {
+            return this.extractor.toString();
+        }
+
+        public int fieldIndex() {
+            return this.fieldIndex;
+        }
+
+        public Object getValue() {
+            if ( this.first == null ) {
+                return null;
+            }
+            return this.extractor.getValue( this.first.getFactHandle().getObject() );
+        }
+
+        public int hashCode() {
+            return this.hashCode;
+        }
+
+        public boolean equals(Object object) {
+            FieldIndexEntry other = (FieldIndexEntry) object;
+            return this.hashCode == other.hashCode && this.fieldIndex == other.fieldIndex;
+        }
+    }    
+}
\ No newline at end of file

Deleted: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/FieldIndexMap.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/FieldIndexMap.java	2006-09-18 20:30:21 UTC (rev 6287)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/FieldIndexMap.java	2006-09-18 22:20:26 UTC (rev 6288)
@@ -1,121 +0,0 @@
-/**
- * 
- */
-package org.drools.util;
-
-import org.drools.common.InternalFactHandle;
-import org.drools.spi.FieldExtractor;
-
-public class FieldIndexMap extends DroolsMap {
-    private int            fieldIndex;
-    private FieldExtractor extractor;
-
-    private final int      PRIME = 31;
-
-    private final int      startResult;
-
-    public FieldIndexMap(int fieldIndex,
-                         FieldExtractor extractor) {
-        this( 16,
-              0.75f,
-              fieldIndex,
-              extractor );
-    }
-
-    public FieldIndexMap(int capacity,
-                         float loadFactor,
-                         int fieldIndex,
-                         FieldExtractor extractor) {
-        super( capacity,
-               loadFactor );
-        this.fieldIndex = fieldIndex;
-        this.extractor = extractor;
-
-        this.startResult = PRIME + this.fieldIndex;
-    }
-
-    public void add(InternalFactHandle handle) {
-        FieldIndexEntry entry = getOrCreate( this.extractor.getValue( handle.getObject() ) );
-        entry.add( handle );
-    }
-
-    public void remove(InternalFactHandle handle) {
-        Object value = this.extractor.getValue( handle.getObject() );
-        int hashCode = PRIME * startResult + ((value == null) ? 0 : value.hashCode());
-
-        int index = indexOf( hashCode, table.length  );
-        
-        // search the table for  the Entry, we need to track previous  and next, so if the 
-        // Entry is empty after  its had the FactEntry removed, we must remove  it from the table
-        FieldIndexEntry previous = ( FieldIndexEntry ) this.table[index];        
-        FieldIndexEntry current = previous;
-        while ( current != null ) {
-            FieldIndexEntry next = ( FieldIndexEntry ) current.getNext();
-            if ( hashCode == current.hashCode() && value.equals( current.getValue() ) ) {
-                current.remove( handle );
-                // If the FactEntryIndex is empty, then remove it from the hash map
-                if (  current.first ==  null  ) {
-                    if( previous  == current ) {
-                        this.table[index] = next;
-                        previous.setNext( next );
-                    }
-                    current.setNext( null );
-                    this.size--;
-                }
-                return;
-            }
-            previous = current;
-            current = next;
-        }
-    }
-
-    public FieldIndexEntry get(Object value) {
-        int hashCode = PRIME * startResult + ((value == null) ? 0 : value.hashCode());
-
-        int index = indexOf( hashCode, table.length  );
-        FieldIndexEntry entry = (FieldIndexEntry) this.table[index];
-
-        while ( entry != null ) {
-            if ( hashCode == entry.hashCode() && value.equals( entry.getValue() ) ) {
-                return entry;
-            }
-            entry = (FieldIndexEntry) entry.getNext();
-        }
-        
-        return entry;
-    }
-    
-
-    /**
-     * We use this method to aviod to table lookups for the same hashcode; which is what we would have to do if we did
-     * a get and then a create if the value is null.
-     * 
-     * @param value
-     * @return
-     */
-    private FieldIndexEntry getOrCreate(Object value) {
-        int hashCode = PRIME * startResult + ((value == null) ? 0 : value.hashCode());
-        int index = indexOf( hashCode, table.length  );
-        FieldIndexEntry entry = (FieldIndexEntry) this.table[index];
-
-        while ( entry != null ) {
-            if ( hashCode == entry.hashCode() && value.equals( entry.getValue() ) ) {
-                return entry;
-            }
-            entry = (FieldIndexEntry) entry.getNext();
-        }        
-
-        if ( entry == null ) {
-            entry = new FieldIndexEntry( this.extractor,
-                                         fieldIndex,
-                                         hashCode );
-            entry.setNext( this.table[index] );
-            this.table[index] = entry;
-
-            if ( this.size++ >= this.threshold ) {
-                resize( 2 * this.table.length );
-            }
-        }
-        return entry;
-    }
-}
\ No newline at end of file

Added: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/ObjectHashMap.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/ObjectHashMap.java	2006-09-18 20:30:21 UTC (rev 6287)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/ObjectHashMap.java	2006-09-18 22:20:26 UTC (rev 6288)
@@ -0,0 +1,167 @@
+/**
+ * 
+ */
+package org.drools.util;
+
+public class ObjectHashMap extends AbstractHashTable {
+    public ObjectHashMap() {
+        this( 16,
+              0.75f );
+    }
+
+    public ObjectHashMap(int capacity,
+                         float loadFactor) {
+        super( capacity,
+               loadFactor );
+    }
+
+    public Object put(Object key,
+                      Object value) {
+        int hashCode = hash( key );
+        int index = indexOf( hashCode,
+                             table.length );
+
+        // scan the linked entries to see if it exists
+        if ( checkExists ) {
+            ObjectEntry current = (ObjectEntry) this.table[index];
+            while ( current != null ) {
+                if ( hashCode == current.hashCode && comparator.equal( key,
+                                                                       current.key ) ) {
+                    Object oldValue = current.value;
+                    current.value = value;
+                    return oldValue;
+                }
+            }
+        }
+
+        // We aren't checking the key exists, or it didn't find the key
+        ObjectEntry entry = new ObjectEntry( key,
+                                             value,
+                                             hashCode );
+        entry.next = this.table[index];
+        this.table[index] = entry;
+
+        if ( this.size++ >= this.threshold ) {
+            resize( 2 * this.table.length );
+        }
+        return null;
+    }
+
+    public Object get(Object key) {
+        int hashCode = hash( key );
+        int index = indexOf( hashCode,
+                             table.length );
+
+        ObjectEntry current = (ObjectEntry) this.table[index];
+        while ( current != null ) {
+            if ( hashCode == current.hashCode && comparator.equal( key,
+                                                                   current.key ) ) {
+                return current.value;
+            }
+            current = (ObjectEntry) current.getNext();
+        }
+        return null;
+    }
+
+    public Object remove(Object key) {
+        int hashCode = hash( key );
+        int index = indexOf( hashCode,
+                             table.length );
+
+        ObjectEntry previous = (ObjectEntry) this.table[index];
+        ObjectEntry current = previous;
+        while ( current != null ) {
+            ObjectEntry next = (ObjectEntry) current.getNext();
+            if ( hashCode == current.hashCode && comparator.equal( key,
+                                                                   current.key ) ) {
+                if ( previous == current ) {
+                    this.table[index] = next;
+                } else {
+                    previous.setNext( next );
+                }
+                current.setNext( null );
+                this.size--;
+                return current;
+            }
+            previous = current;
+            current = next;
+        }
+        return current;
+    }
+    
+    public Entry getBucket(int hashCode) {
+        int h = hashCode;
+        h += ~(h << 9);
+        h ^= (h >>> 14);
+        h += (h << 4);
+        h ^= (h >>> 10);
+        
+        return this.table[ indexOf( h, table.length ) ];
+    }    
+
+    public int hash(Object key) {
+        int h = key.hashCode();
+        h += ~(h << 9);
+        h ^= (h >>> 14);
+        h += (h << 4);
+        h ^= (h >>> 10);
+        return h;
+    }
+
+    protected int indexOf(int hashCode,
+                          int dataSize) {
+        return hashCode & (dataSize - 1);
+    }
+
+    private static class ObjectEntry
+        implements
+        Entry {
+        private Object key;
+
+        private Object value;
+
+        private int    hashCode;
+
+        private Entry next;
+
+        public ObjectEntry(Object key,
+                           Object value,
+                           int hashCode) {
+            this.key = key;
+            this.value = value;
+            this.hashCode = hashCode;
+        }
+
+        public Object getValue() {
+            return value;
+        }
+
+
+        public Object getKey() {
+            return key;
+        }
+
+        public Entry getNext() {
+            return this.next;
+        }
+
+        public void setNext(Entry next) {
+            this.next = next;
+        }
+
+        public int hashCode() {
+            return this.key.hashCode() ^ this.value.hashCode();
+        }
+
+        public boolean equals(Object object) {
+            if ( object == this ) {
+                return true;
+            }
+
+            // assumes we never have null or wrong class
+
+            ObjectEntry other = (ObjectEntry) object;
+            return this.key.equals( other.key ) && this.value.equals( other.value );
+        }
+    }
+}
\ No newline at end of file

Modified: labs/jbossrules/trunk/drools-core/src/test/java/org/drools/util/FieldIndexEntryTest.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/test/java/org/drools/util/FieldIndexEntryTest.java	2006-09-18 20:30:21 UTC (rev 6287)
+++ labs/jbossrules/trunk/drools-core/src/test/java/org/drools/util/FieldIndexEntryTest.java	2006-09-18 22:20:26 UTC (rev 6288)
@@ -4,6 +4,7 @@
 import org.drools.base.ClassFieldExtractor;
 import org.drools.common.DefaultFactHandle;
 import org.drools.common.InternalFactHandle;
+import org.drools.util.FieldIndexHashTable.FieldIndexEntry;
 
 import junit.framework.TestCase;
 

Copied: labs/jbossrules/trunk/drools-core/src/test/java/org/drools/util/FieldIndexHashTableTest.java (from rev 6284, labs/jbossrules/trunk/drools-core/src/test/java/org/drools/util/FieldIndexMapTest.java)
===================================================================
--- labs/jbossrules/trunk/drools-core/src/test/java/org/drools/util/FieldIndexMapTest.java	2006-09-18 19:14:03 UTC (rev 6284)
+++ labs/jbossrules/trunk/drools-core/src/test/java/org/drools/util/FieldIndexHashTableTest.java	2006-09-18 22:20:26 UTC (rev 6288)
@@ -0,0 +1,314 @@
+package org.drools.util;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.drools.Cheese;
+import org.drools.base.ClassFieldExtractor;
+import org.drools.common.DefaultFactHandle;
+import org.drools.common.InternalFactHandle;
+import org.drools.util.FieldIndexHashTable.FieldIndexEntry;
+
+public class FieldIndexHashTableTest extends TestCase {
+    
+    public void testSingleEntry() throws Exception {
+        ClassFieldExtractor extractor = new ClassFieldExtractor(Cheese.class, "type");
+        
+        FieldIndexHashTable map = new FieldIndexHashTable( extractor.getIndex(), extractor );
+        
+        assertEquals(0, map.size() );
+        
+        assertNull( map.get( "cheddar" ) );
+        
+        Cheese stilton1 = new Cheese("stilton", 35);
+        InternalFactHandle stiltonHandle1 = new DefaultFactHandle( 1, stilton1 );   
+        map.add( stiltonHandle1 );
+        
+        assertEquals(1, map.size() );        
+        assertEquals( 1, tablePopulationSize( map ) );
+        
+        FieldIndexEntry stiltonEntry = map.get( "stilton" );
+        assertSame( stiltonHandle1, stiltonEntry.getFirst().getFactHandle() );
+        assertNull( stiltonEntry.getFirst().getNext() );               
+    }
+    
+    public void testTwoDifferentEntries() throws Exception {
+        ClassFieldExtractor extractor = new ClassFieldExtractor(Cheese.class, "type");
+        
+        FieldIndexHashTable map = new FieldIndexHashTable( extractor.getIndex(), extractor );
+        
+        assertEquals(0, map.size() );
+        
+        Cheese stilton1 = new Cheese("stilton", 35);
+        InternalFactHandle stiltonHandle1 = new DefaultFactHandle( 1, stilton1 );   
+        map.add( stiltonHandle1 );                
+        
+        Cheese cheddar1 = new Cheese("cheddar", 35);
+        InternalFactHandle cheddarHandle1 = new DefaultFactHandle( 2, cheddar1 );   
+        map.add( cheddarHandle1 );        
+        
+        assertEquals(2, map.size() );      
+        assertEquals( 2, tablePopulationSize( map ) );
+        
+        FieldIndexEntry stiltonEntry = map.get( "stilton" );
+        assertSame( stiltonHandle1, stiltonEntry.getFirst().getFactHandle() );
+        assertNull( stiltonEntry.getFirst().getNext() );         
+        
+        FieldIndexEntry cheddarEntry = map.get( "cheddar" );
+        assertSame( cheddarHandle1, cheddarEntry.getFirst().getFactHandle() );
+        assertNull( cheddarEntry.getFirst().getNext() );                
+    }    
+    
+    public void testTwoEqualEntries() throws  Exception {
+        ClassFieldExtractor extractor = new ClassFieldExtractor(Cheese.class, "type");
+        
+        FieldIndexHashTable map = new FieldIndexHashTable( extractor.getIndex(), extractor );
+        
+        assertEquals(0, map.size() );
+        
+        Cheese stilton1 = new Cheese("stilton", 35);
+        InternalFactHandle stiltonHandle1 = new DefaultFactHandle( 1, stilton1 );   
+        map.add( stiltonHandle1 );                
+        
+        Cheese cheddar1 = new Cheese("cheddar", 35);
+        InternalFactHandle cheddarHandle1 = new DefaultFactHandle( 2, cheddar1 );   
+        map.add( cheddarHandle1 );           
+        
+        Cheese stilton2 = new Cheese("stilton", 81);
+        InternalFactHandle stiltonHandle2 = new DefaultFactHandle( 3, stilton2 );   
+        map.add( stiltonHandle2 );
+        
+        // Two siltons are in the same index bucket, so it won't increase the map size
+        assertEquals(2, map.size() );
+        assertEquals( 2, tablePopulationSize( map ) );
+        
+        // Check they are correctly chained to the same FieldIndexEntry
+        FieldIndexEntry stiltonEntry = map.get( "stilton" );
+        assertSame( stiltonHandle2, stiltonEntry.getFirst().getFactHandle() );
+        assertSame( stiltonHandle1, ((FactEntry)stiltonEntry.getFirst().getNext()).getFactHandle() );             
+    }      
+    
+    public void testTwoDifferentEntriesSameHashCode() throws Exception  {
+        ClassFieldExtractor extractor = new ClassFieldExtractor(TestClass.class, "object");
+        
+        FieldIndexHashTable map = new FieldIndexHashTable( extractor.getIndex(), extractor );
+        
+        TestClass c1 = new TestClass( 0, new TestClass( 20, "stilton" ) );
+        InternalFactHandle ch1 = new DefaultFactHandle( 1, c1 );
+        
+        map.add( ch1 );
+        
+        TestClass c2 = new TestClass( 0, new TestClass( 20, "cheddar" ) );
+        InternalFactHandle ch2 = new DefaultFactHandle( 2, c2 );
+        map.add( ch2 );
+        
+        // same hashcode, but different values, so it should result in  a size of 2
+        assertEquals(2, map.size() );
+        
+        // however both are in the same table bucket
+        assertEquals( 1, tablePopulationSize( map ) );
+        
+        
+        // this table bucket will have two FieldIndexEntries, as they are actually two different values
+        FieldIndexEntry entry = (FieldIndexEntry) getEntries( map )[0];
+        
+        assertEquals( c2.getObject(), entry.getValue());
+        assertEquals( c1.getObject(), ((FieldIndexEntry) entry.getNext()).getValue());                    
+    }   
+    
+    public void testRemove() throws Exception {
+        ClassFieldExtractor extractor = new ClassFieldExtractor(Cheese.class, "type");
+        
+        FieldIndexHashTable map = new FieldIndexHashTable( extractor.getIndex(), extractor );
+        
+        assertEquals(0, map.size() );
+        
+        Cheese stilton1 = new Cheese("stilton", 35);
+        InternalFactHandle stiltonHandle1 = new DefaultFactHandle( 1, stilton1 );   
+        map.add( stiltonHandle1 );                
+        
+        Cheese cheddar1 = new Cheese("cheddar", 35);
+        InternalFactHandle cheddarHandle1 = new DefaultFactHandle( 2, cheddar1 );   
+        map.add( cheddarHandle1 );           
+        
+        Cheese stilton2 = new Cheese("stilton", 81);
+        InternalFactHandle stiltonHandle2 = new DefaultFactHandle( 3, stilton2 );   
+        map.add( stiltonHandle2 );
+        
+        // Two siltons are in the same index bucket, so it won't increase the map size
+        assertEquals(2, map.size() );
+        assertEquals( 2, tablePopulationSize( map ) ); 
+        
+        // cheddar is in its own buccket, which should be removed once empty. We cannot have
+        // empty FieldIndexEntries in the Map, as they get their value  from the first FactEntry.
+        map.remove( cheddarHandle1 );
+        assertEquals( 1, map.size() );      
+        assertEquals( 1, tablePopulationSize( map ) );     
+        
+        // We remove t he stiltonHandle2, but there is still  one more stilton, so size  should be the same
+        map.remove( stiltonHandle2 );
+        assertEquals( 1, map.size() );      
+        assertEquals( 1, tablePopulationSize( map ) );   
+        
+        //  No more stiltons, so the table should be empty
+        map.remove( stiltonHandle1 );
+        assertEquals( 0, map.size() );      
+        assertEquals( 0, tablePopulationSize( map ) );           
+    }
+    
+    public void  testResize() throws Exception {
+        // use this  to access  the  map table
+        Field field = AbstractHashTable.class.getDeclaredField( "table" );
+        field.setAccessible( true );
+        
+        // This should  only resize when we have more than X different types of cheeses, not before.
+        ClassFieldExtractor extractor = new ClassFieldExtractor(Cheese.class, "type");
+        
+        FieldIndexHashTable map = new FieldIndexHashTable( extractor.getIndex(), extractor );
+        
+        assertEquals(0, map.size() );
+        
+        Cheese stilton1 = new Cheese("stilton", 35);   
+        map.add( new DefaultFactHandle( 1, stilton1 ) );                
+
+        Cheese stilton2 = new Cheese("stilton", 81);   
+        map.add( new DefaultFactHandle( 2, stilton2 ) );
+        
+        Cheese cheddar1 = new Cheese("cheddar", 35);   
+        map.add( new DefaultFactHandle( 3, cheddar1 ) );           
+        
+        Cheese cheddar2 = new Cheese("cheddar", 38);   
+        map.add( new DefaultFactHandle( 4, cheddar2 ) );
+        
+        Cheese brie = new Cheese("brie", 293);   
+        map.add( new DefaultFactHandle( 5, brie ) );        
+
+        Cheese mozerella = new Cheese("mozerella", 15);   
+        map.add( new DefaultFactHandle( 6, mozerella ) );
+        
+        Cheese dolcelatte = new Cheese("dolcelatte", 284);   
+        map.add( new DefaultFactHandle( 7, dolcelatte ) );
+        
+        Cheese camembert1 = new Cheese("camembert", 924);   
+        map.add( new DefaultFactHandle( 8, camembert1 ) );        
+
+        Cheese camembert2 = new Cheese("camembert", 765);   
+        map.add( new DefaultFactHandle( 9, camembert2 ) );
+        
+        Cheese redLeicestor = new Cheese("red leicestor", 23);   
+        map.add( new DefaultFactHandle( 10, redLeicestor ) );                
+        
+        Cheese wensleydale = new Cheese("wensleydale", 20);   
+        map.add( new DefaultFactHandle( 11, wensleydale ) );        
+
+        Cheese edam = new Cheese("edam", 12);   
+        map.add( new DefaultFactHandle( 12, edam ) );
+        
+        Cheese goude1 = new Cheese("goude", 93);   
+        map.add( new DefaultFactHandle( 13, goude1 ) );                  
+
+        Cheese goude2 = new Cheese("goude", 88);   
+        map.add( new DefaultFactHandle( 14, goude2 ) );            
+        
+        Cheese gruyere = new Cheese("gruyere", 82);   
+        map.add( new DefaultFactHandle( 15, gruyere ) );                  
+        
+        Cheese emmental = new Cheese("emmental", 98);   
+        map.add( new DefaultFactHandle( 16, emmental ) );           
+        
+        // At this point we have 16 facts but only 12 different types of cheeses
+        // so no table resize and thus its size is 16
+        
+        assertEquals( 12, map.size() );
+        
+        Entry[] table = (Entry[]) field.get( map );
+        assertEquals( 16, table.length);           
+        
+        Cheese feta = new Cheese("feta", 48);   
+        map.add( new DefaultFactHandle( 2, feta ) );
+        
+        // This adds our 13th type of cheese. The map is set with an initial capacity of 16 and
+        // a threshold of 75%, that after 12 it should resize the map to 32.
+        assertEquals( 13, map.size() );
+        
+        table = (Entry[]) field.get( map );
+        assertEquals( 32, table.length);  
+        
+        Cheese haloumi = new Cheese("haloumi", 48);   
+        map.add( new DefaultFactHandle( 2, haloumi ) );
+        
+        Cheese chevre = new Cheese("chevre", 48);   
+        map.add( new DefaultFactHandle( 2, chevre ) );    
+                                                
+    }
+    
+    public static class TestClass {
+        private int hashCode;
+        private Object object;
+        
+        public TestClass(){
+            
+        }
+        
+        public TestClass(int hashCode,
+                         Object object) {
+            this.hashCode = hashCode;
+            this.object = object;
+        }
+        
+        public Object getObject() {
+            return this.object;
+        }
+        public void setObject(Object object) {
+            this.object = object;
+        }
+        public void setHashCode(int hashCode) {
+            this.hashCode = hashCode;
+        }
+        public int hashCode() {
+            return this.hashCode;
+        }
+        public boolean equals(Object obj) {
+            if ( this == obj ) return true;
+            if ( obj == null ) return false;
+            if ( getClass() != obj.getClass() ) return false;
+            final TestClass other = (TestClass) obj;
+
+            if ( this.object == null ) {
+                if ( other.object != null ) return false;
+            } else if ( !this.object.equals( other.object ) ) return false;
+            return true;
+        }                        
+    }
+    
+    private int tablePopulationSize(AbstractHashTable map) throws Exception {
+        Field field = AbstractHashTable.class.getDeclaredField( "table" );
+        field.setAccessible( true );
+        Entry[] array = (Entry[]) field.get( map );
+        int size = 0;
+        for ( int i = 0, length = array.length; i  < length; i++  ) {
+            if  ( array[i]  != null ) {
+                size++;
+            }
+        }
+        return size;
+    }
+    
+    private Entry[] getEntries(AbstractHashTable map) throws Exception {
+        Field field = AbstractHashTable.class.getDeclaredField( "table" );
+        field.setAccessible( true );
+        List list = new ArrayList();
+        
+        Entry[] array = (Entry[]) field.get( map );
+        for ( int i = 0, length = array.length; i  < length; i++  ) {
+            if ( array[i] != null ) {
+                list.add( array[i]);
+            }
+        }
+        return ( Entry[] ) list.toArray( new Entry[ list.size() ] );
+    }    
+    
+}

Deleted: labs/jbossrules/trunk/drools-core/src/test/java/org/drools/util/FieldIndexMapTest.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/test/java/org/drools/util/FieldIndexMapTest.java	2006-09-18 20:30:21 UTC (rev 6287)
+++ labs/jbossrules/trunk/drools-core/src/test/java/org/drools/util/FieldIndexMapTest.java	2006-09-18 22:20:26 UTC (rev 6288)
@@ -1,313 +0,0 @@
-package org.drools.util;
-
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.List;
-
-import junit.framework.TestCase;
-
-import org.drools.Cheese;
-import org.drools.base.ClassFieldExtractor;
-import org.drools.common.DefaultFactHandle;
-import org.drools.common.InternalFactHandle;
-
-public class FieldIndexMapTest extends TestCase {
-    
-    public void testSingleEntry() throws Exception {
-        ClassFieldExtractor extractor = new ClassFieldExtractor(Cheese.class, "type");
-        
-        FieldIndexMap map = new FieldIndexMap( extractor.getIndex(), extractor );
-        
-        assertEquals(0, map.size() );
-        
-        assertNull( map.get( "cheddar" ) );
-        
-        Cheese stilton1 = new Cheese("stilton", 35);
-        InternalFactHandle stiltonHandle1 = new DefaultFactHandle( 1, stilton1 );   
-        map.add( stiltonHandle1 );
-        
-        assertEquals(1, map.size() );        
-        assertEquals( 1, tablePopulationSize( map ) );
-        
-        FieldIndexEntry stiltonEntry = map.get( "stilton" );
-        assertSame( stiltonHandle1, stiltonEntry.getFirst().getFactHandle() );
-        assertNull( stiltonEntry.getFirst().getNext() );               
-    }
-    
-    public void testTwoDifferentEntries() throws Exception {
-        ClassFieldExtractor extractor = new ClassFieldExtractor(Cheese.class, "type");
-        
-        FieldIndexMap map = new FieldIndexMap( extractor.getIndex(), extractor );
-        
-        assertEquals(0, map.size() );
-        
-        Cheese stilton1 = new Cheese("stilton", 35);
-        InternalFactHandle stiltonHandle1 = new DefaultFactHandle( 1, stilton1 );   
-        map.add( stiltonHandle1 );                
-        
-        Cheese cheddar1 = new Cheese("cheddar", 35);
-        InternalFactHandle cheddarHandle1 = new DefaultFactHandle( 2, cheddar1 );   
-        map.add( cheddarHandle1 );        
-        
-        assertEquals(2, map.size() );      
-        assertEquals( 2, tablePopulationSize( map ) );
-        
-        FieldIndexEntry stiltonEntry = map.get( "stilton" );
-        assertSame( stiltonHandle1, stiltonEntry.getFirst().getFactHandle() );
-        assertNull( stiltonEntry.getFirst().getNext() );         
-        
-        FieldIndexEntry cheddarEntry = map.get( "cheddar" );
-        assertSame( cheddarHandle1, cheddarEntry.getFirst().getFactHandle() );
-        assertNull( cheddarEntry.getFirst().getNext() );                
-    }    
-    
-    public void testTwoEqualEntries() throws  Exception {
-        ClassFieldExtractor extractor = new ClassFieldExtractor(Cheese.class, "type");
-        
-        FieldIndexMap map = new FieldIndexMap( extractor.getIndex(), extractor );
-        
-        assertEquals(0, map.size() );
-        
-        Cheese stilton1 = new Cheese("stilton", 35);
-        InternalFactHandle stiltonHandle1 = new DefaultFactHandle( 1, stilton1 );   
-        map.add( stiltonHandle1 );                
-        
-        Cheese cheddar1 = new Cheese("cheddar", 35);
-        InternalFactHandle cheddarHandle1 = new DefaultFactHandle( 2, cheddar1 );   
-        map.add( cheddarHandle1 );           
-        
-        Cheese stilton2 = new Cheese("stilton", 81);
-        InternalFactHandle stiltonHandle2 = new DefaultFactHandle( 3, stilton2 );   
-        map.add( stiltonHandle2 );
-        
-        // Two siltons are in the same index bucket, so it won't increase the map size
-        assertEquals(2, map.size() );
-        assertEquals( 2, tablePopulationSize( map ) );
-        
-        // Check they are correctly chained to the same FieldIndexEntry
-        FieldIndexEntry stiltonEntry = map.get( "stilton" );
-        assertSame( stiltonHandle2, stiltonEntry.getFirst().getFactHandle() );
-        assertSame( stiltonHandle1, ((FactEntry)stiltonEntry.getFirst().getNext()).getFactHandle() );             
-    }      
-    
-    public void testTwoDifferentEntriesSameHashCode() throws Exception  {
-        ClassFieldExtractor extractor = new ClassFieldExtractor(TestClass.class, "object");
-        
-        FieldIndexMap map = new FieldIndexMap( extractor.getIndex(), extractor );
-        
-        TestClass c1 = new TestClass( 0, new TestClass( 20, "stilton" ) );
-        InternalFactHandle ch1 = new DefaultFactHandle( 1, c1 );
-        
-        map.add( ch1 );
-        
-        TestClass c2 = new TestClass( 0, new TestClass( 20, "cheddar" ) );
-        InternalFactHandle ch2 = new DefaultFactHandle( 2, c2 );
-        map.add( ch2 );
-        
-        // same hashcode, but different values, so it should result in  a size of 2
-        assertEquals(2, map.size() );
-        
-        // however both are in the same table bucket
-        assertEquals( 1, tablePopulationSize( map ) );
-        
-        
-        // this table bucket will have two FieldIndexEntries, as they are actually two different values
-        FieldIndexEntry entry = (FieldIndexEntry) getEntries( map )[0];
-        
-        assertEquals( c2.getObject(), entry.getValue());
-        assertEquals( c1.getObject(), ((FieldIndexEntry) entry.getNext()).getValue());                    
-    }   
-    
-    public void testRemove() throws Exception {
-        ClassFieldExtractor extractor = new ClassFieldExtractor(Cheese.class, "type");
-        
-        FieldIndexMap map = new FieldIndexMap( extractor.getIndex(), extractor );
-        
-        assertEquals(0, map.size() );
-        
-        Cheese stilton1 = new Cheese("stilton", 35);
-        InternalFactHandle stiltonHandle1 = new DefaultFactHandle( 1, stilton1 );   
-        map.add( stiltonHandle1 );                
-        
-        Cheese cheddar1 = new Cheese("cheddar", 35);
-        InternalFactHandle cheddarHandle1 = new DefaultFactHandle( 2, cheddar1 );   
-        map.add( cheddarHandle1 );           
-        
-        Cheese stilton2 = new Cheese("stilton", 81);
-        InternalFactHandle stiltonHandle2 = new DefaultFactHandle( 3, stilton2 );   
-        map.add( stiltonHandle2 );
-        
-        // Two siltons are in the same index bucket, so it won't increase the map size
-        assertEquals(2, map.size() );
-        assertEquals( 2, tablePopulationSize( map ) ); 
-        
-        // cheddar is in its own buccket, which should be removed once empty. We cannot have
-        // empty FieldIndexEntries in the Map, as they get their value  from the first FactEntry.
-        map.remove( cheddarHandle1 );
-        assertEquals( 1, map.size() );      
-        assertEquals( 1, tablePopulationSize( map ) );     
-        
-        // We remove t he stiltonHandle2, but there is still  one more stilton, so size  should be the same
-        map.remove( stiltonHandle2 );
-        assertEquals( 1, map.size() );      
-        assertEquals( 1, tablePopulationSize( map ) );   
-        
-        //  No more stiltons, so the table should be empty
-        map.remove( stiltonHandle1 );
-        assertEquals( 0, map.size() );      
-        assertEquals( 0, tablePopulationSize( map ) );           
-    }
-    
-    public void  testResize() throws Exception {
-        // use this  to access  the  map table
-        Field field = DroolsMap.class.getDeclaredField( "table" );
-        field.setAccessible( true );
-        
-        // This should  only resize when we have more than X different types of cheeses, not before.
-        ClassFieldExtractor extractor = new ClassFieldExtractor(Cheese.class, "type");
-        
-        FieldIndexMap map = new FieldIndexMap( extractor.getIndex(), extractor );
-        
-        assertEquals(0, map.size() );
-        
-        Cheese stilton1 = new Cheese("stilton", 35);   
-        map.add( new DefaultFactHandle( 1, stilton1 ) );                
-
-        Cheese stilton2 = new Cheese("stilton", 81);   
-        map.add( new DefaultFactHandle( 2, stilton2 ) );
-        
-        Cheese cheddar1 = new Cheese("cheddar", 35);   
-        map.add( new DefaultFactHandle( 3, cheddar1 ) );           
-        
-        Cheese cheddar2 = new Cheese("cheddar", 38);   
-        map.add( new DefaultFactHandle( 4, cheddar2 ) );
-        
-        Cheese brie = new Cheese("brie", 293);   
-        map.add( new DefaultFactHandle( 5, brie ) );        
-
-        Cheese mozerella = new Cheese("mozerella", 15);   
-        map.add( new DefaultFactHandle( 6, mozerella ) );
-        
-        Cheese dolcelatte = new Cheese("dolcelatte", 284);   
-        map.add( new DefaultFactHandle( 7, dolcelatte ) );
-        
-        Cheese camembert1 = new Cheese("camembert", 924);   
-        map.add( new DefaultFactHandle( 8, camembert1 ) );        
-
-        Cheese camembert2 = new Cheese("camembert", 765);   
-        map.add( new DefaultFactHandle( 9, camembert2 ) );
-        
-        Cheese redLeicestor = new Cheese("red leicestor", 23);   
-        map.add( new DefaultFactHandle( 10, redLeicestor ) );                
-        
-        Cheese wensleydale = new Cheese("wensleydale", 20);   
-        map.add( new DefaultFactHandle( 11, wensleydale ) );        
-
-        Cheese edam = new Cheese("edam", 12);   
-        map.add( new DefaultFactHandle( 12, edam ) );
-        
-        Cheese goude1 = new Cheese("goude", 93);   
-        map.add( new DefaultFactHandle( 13, goude1 ) );                  
-
-        Cheese goude2 = new Cheese("goude", 88);   
-        map.add( new DefaultFactHandle( 14, goude2 ) );            
-        
-        Cheese gruyere = new Cheese("gruyere", 82);   
-        map.add( new DefaultFactHandle( 15, gruyere ) );                  
-        
-        Cheese emmental = new Cheese("emmental", 98);   
-        map.add( new DefaultFactHandle( 16, emmental ) );           
-        
-        // At this point we have 16 facts but only 12 different types of cheeses
-        // so no table resize and thus its size is 16
-        
-        assertEquals( 12, map.size() );
-        
-        Entry[] table = (Entry[]) field.get( map );
-        assertEquals( 16, table.length);           
-        
-        Cheese feta = new Cheese("feta", 48);   
-        map.add( new DefaultFactHandle( 2, feta ) );
-        
-        // This adds our 13th type of cheese. The map is set with an initial capacity of 16 and
-        // a threshold of 75%, that after 12 it should resize the map to 32.
-        assertEquals( 13, map.size() );
-        
-        table = (Entry[]) field.get( map );
-        assertEquals( 32, table.length);  
-        
-        Cheese haloumi = new Cheese("haloumi", 48);   
-        map.add( new DefaultFactHandle( 2, haloumi ) );
-        
-        Cheese chevre = new Cheese("chevre", 48);   
-        map.add( new DefaultFactHandle( 2, chevre ) );    
-                                                
-    }
-    
-    public static class TestClass {
-        private int hashCode;
-        private Object object;
-        
-        public TestClass(){
-            
-        }
-        
-        public TestClass(int hashCode,
-                         Object object) {
-            this.hashCode = hashCode;
-            this.object = object;
-        }
-        
-        public Object getObject() {
-            return this.object;
-        }
-        public void setObject(Object object) {
-            this.object = object;
-        }
-        public void setHashCode(int hashCode) {
-            this.hashCode = hashCode;
-        }
-        public int hashCode() {
-            return this.hashCode;
-        }
-        public boolean equals(Object obj) {
-            if ( this == obj ) return true;
-            if ( obj == null ) return false;
-            if ( getClass() != obj.getClass() ) return false;
-            final TestClass other = (TestClass) obj;
-
-            if ( this.object == null ) {
-                if ( other.object != null ) return false;
-            } else if ( !this.object.equals( other.object ) ) return false;
-            return true;
-        }                        
-    }
-    
-    private int tablePopulationSize(DroolsMap map) throws Exception {
-        Field field = DroolsMap.class.getDeclaredField( "table" );
-        field.setAccessible( true );
-        Entry[] array = (Entry[]) field.get( map );
-        int size = 0;
-        for ( int i = 0, length = array.length; i  < length; i++  ) {
-            if  ( array[i]  != null ) {
-                size++;
-            }
-        }
-        return size;
-    }
-    
-    private Entry[] getEntries(DroolsMap map) throws Exception {
-        Field field = DroolsMap.class.getDeclaredField( "table" );
-        field.setAccessible( true );
-        List list = new ArrayList();
-        
-        Entry[] array = (Entry[]) field.get( map );
-        for ( int i = 0, length = array.length; i  < length; i++  ) {
-            if ( array[i] != null ) {
-                list.add( array[i]);
-            }
-        }
-        return ( Entry[] ) list.toArray( new Entry[ list.size() ] );
-    }    
-    
-}

Added: labs/jbossrules/trunk/drools-core/src/test/java/org/drools/util/ObjectHashMapTest.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/test/java/org/drools/util/ObjectHashMapTest.java	2006-09-18 20:30:21 UTC (rev 6287)
+++ labs/jbossrules/trunk/drools-core/src/test/java/org/drools/util/ObjectHashMapTest.java	2006-09-18 22:20:26 UTC (rev 6288)
@@ -0,0 +1,80 @@
+package org.drools.util;
+
+import junit.framework.TestCase;
+
+import org.drools.Cheese;
+
+public class ObjectHashMapTest extends TestCase {
+	public void testChechExistsFalse() {
+		ObjectHashMap map = new ObjectHashMap();
+		Cheese stilton = new Cheese("stilton", 5);
+		map.put(new Integer(1), stilton);
+		
+		Cheese c = (Cheese) map.get(new Integer(1));
+		assertSame(stilton, c);
+        
+        // we haven't told the map to check if the key exists, so we should end up with two entries.
+        // the second one is nolonger reacheable
+        Cheese cheddar = new Cheese("cheddar", 5);
+        map.put(new Integer(1), cheddar);
+        c = (Cheese) map.get(new Integer(1));
+        assertSame(cheddar, c);
+        
+        Entry entry = map.getBucket( new Integer(1).hashCode() );
+        int size = 0;
+        while ( entry != null ) {
+            size++;
+            entry = entry.getNext();
+        }
+        
+        assertEquals( 2, size);
+        
+        // Check remove works, should leave one unreachable key
+        map.remove( new Integer(1) );
+        entry = map.getBucket( new Integer(1).hashCode() );
+        size = 0;
+        while ( entry != null ) {
+            size++;
+            entry = entry.getNext();
+        }
+        
+        assertEquals( 1, size);        
+	}
+    
+    public void testChechExistsTrue() {
+        ObjectHashMap map = new ObjectHashMap();
+        map.setCheckExists( true );
+        Cheese stilton = new Cheese("stilton", 5);
+        map.put(new Integer(1), stilton);
+        
+        Cheese c = (Cheese) map.get(new Integer(1));
+        assertSame(stilton, c);
+        
+        // we haven't told the map to check if the key exists, so we should end up with two entries.
+        // the second one is nolonger reacheable
+        Cheese cheddar = new Cheese("cheddar", 5);
+        map.put(new Integer(1), cheddar);
+        c = (Cheese) map.get(new Integer(1));
+        assertSame(cheddar, c);
+        
+        Entry entry = map.getBucket( new Integer(1).hashCode() );
+        int size = 0;
+        while ( entry != null ) {
+            size++;
+            entry = entry.getNext();
+        }
+        
+        assertEquals( 1, size);    
+        
+        // Check remove works
+        map.remove( new Integer(1) );
+        entry = map.getBucket( new Integer(1).hashCode() );
+        size = 0;
+        while ( entry != null ) {
+            size++;
+            entry = entry.getNext();
+        }
+        
+        assertEquals( 0, size);          
+    }
+}




More information about the jboss-svn-commits mailing list