/**
* Copyright 2010 JBoss Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
*
*/
package org.drools.core.util;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.drools.reteoo.LeftTuple;
import org.drools.rule.Declaration;
import org.drools.spi.Evaluator;
import org.drools.spi.InternalReadAccessor;
import org.drools.spi.ReadAccessor;
public abstract class AbstractHashTable
implements
Externalizable {
static final int MAX_CAPACITY = 1 << 30;
protected int size;
protected int threshold;
protected float loadFactor;
protected ObjectComparator comparator;
protected Entry[] table;
private HashTableIterator iterator;
public AbstractHashTable() {
this( 16,
0.75f );
}
public AbstractHashTable(final int capacity,
final float loadFactor) {
this.loadFactor = loadFactor;
this.threshold = (int) (capacity * loadFactor);
this.table = new Entry[capacity];
this.comparator = EqualityEquals.getInstance();
}
public AbstractHashTable(final Entry[] table) {
this( 0.75f,
table );
}
public AbstractHashTable(final float loadFactor,
final Entry[] table) {
this.loadFactor = loadFactor;
this.threshold = (int) (table.length * loadFactor);
this.table = table;
this.comparator = EqualityEquals.getInstance();
}
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
size = in.readInt();
threshold = in.readInt();
loadFactor = in.readFloat();
comparator = (ObjectComparator) in.readObject();
table = (Entry[]) in.readObject();
iterator = (HashTableIterator) in.readObject();
}
public void writeExternal(ObjectOutput out) throws IOException {
out.writeInt( size );
out.writeInt( threshold );
out.writeFloat( loadFactor );
out.writeObject( comparator );
out.writeObject( table );
out.writeObject( iterator );
}
public Iterator iterator() {
if ( this.iterator == null ) {
this.iterator = new HashTableIterator( this );
} else {
this.iterator.reset();
}
return this.iterator;
}
public Iterator newIterator() {
HashTableIterator iterator = new HashTableIterator( this );
iterator.reset();
return iterator;
}
public void setComparator(final ObjectComparator comparator) {
this.comparator = comparator;
}
protected void resize(final int newCapacity) {
final Entry[] oldTable = this.table;
final int oldCapacity = oldTable.length;
if ( oldCapacity == AbstractHashTable.MAX_CAPACITY ) {
this.threshold = Integer.MAX_VALUE;
return;
}
final 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();
final 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 Entry[] toArray() {
Entry[] result = new Entry[this.size];
int index = 0;
for ( int i = 0; i < this.table.length; i++ ) {
Entry entry = this.table[i];
while ( entry != null ) {
result[index++] = entry;
entry = entry.getNext();
}
}
return result;
}
// 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;
// }
protected Entry getBucket(final int hashCode) {
return this.table[indexOf( hashCode,
this.table.length )];
}
public Entry[] getTable() {
return this.table;
}
public int size() {
return this.size;
}
public boolean isEmpty() {
return this.size == 0;
}
// protected int indexOf(int hashCode,
// int dataSize) {
// int index = hashCode % dataSize;
// if ( index < 0 ) {
// index = index * -1;
// }
// return index;
// }
protected int indexOf(final int hashCode,
final int dataSize) {
return hashCode & (dataSize - 1);
}
public abstract Entry getBucket(Object object);
public interface ObjectComparator
extends
Externalizable {
public int hashCodeOf(Object object);
public int rehash(int hashCode);
public boolean equal(Object object1,
Object object2);
}
/**
* Fast re-usable iterator
*
*/
public static class HashTableIterator
implements
Iterator,
Externalizable {
private static final long serialVersionUID = 510l;
private AbstractHashTable hashTable;
private Entry[] table;
private int row;
private int length;
private Entry entry;
public HashTableIterator() {
}
public HashTableIterator(final AbstractHashTable hashTable) {
this.hashTable = hashTable;
reset();
}
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
hashTable = (AbstractHashTable) in.readObject();
table = (Entry[]) in.readObject();
row = in.readInt();
length = in.readInt();
entry = (Entry) in.readObject();
}
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject( hashTable );
out.writeObject( table );
out.writeInt( row );
out.writeInt( length );
out.writeObject( entry );
}
/* (non-Javadoc)
* @see org.drools.util.Iterator#next()
*/
public Object next() {
if ( this.entry != null ) {
this.entry = this.entry.getNext();
}
// if no entry keep skipping rows until we come to the end, or find one that is populated
while ( this.entry == null && ++this.row < this.length ){
this.entry = this.table[this.row];
}
return this.entry;
}
// /* (non-Javadoc)
// * @see org.drools.util.Iterator#next()
// */
// public Object next() {
// if ( this.entry == null ) {
// // keep skipping rows until we come to the end, or find one that is populated
// while ( this.entry == null ) {
// this.row++;
// if ( this.row == this.length ) {
// return null;
// }
// this.entry = this.table[this.row];
// }
// } else {
// this.entry = this.entry.getNext();
// if ( this.entry == null ) {
// this.entry = (Entry) next();
// }
// }
//
// return this.entry;
// }
// /* (non-Javadoc)
// * @see org.drools.util.Iterator#next()
// */
// public Object next() {
// if ( this.entry == null ) {
// // keep skipping rows until we come to the end, or find one that is populated
// while ( this.entry == null ) {
// this.row++;
// if ( this.row == this.length ) {
// return null;
// }
// this.entry = this.table[this.row];
// }
// } else {
// this.entry = this.entry.getNext();
// if ( this.entry == null ) {
// this.entry = (Entry) next();
// }
// }
//
// return this.entry;
// }
/* (non-Javadoc)
* @see org.drools.util.Iterator#reset()
*/
public void reset() {
this.table = this.hashTable.getTable();
this.length = this.table.length;
this.row = -1;
this.entry = null;
}
}
public static class InstanceEquals
implements
ObjectComparator {
private static final long serialVersionUID = 510l;
public static ObjectComparator INSTANCE = new InstanceEquals();
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
}
public void writeExternal(ObjectOutput out) throws IOException {
}
public static ObjectComparator getInstance() {
return InstanceEquals.INSTANCE;
}
public int hashCodeOf(final Object key) {
return rehash( key.hashCode() );
}
public int rehash(int h) {
h += ~(h << 9);
h ^= (h >>> 14);
h += (h << 4);
h ^= (h >>> 10);
return h;
}
private InstanceEquals() {
}
public boolean equal(final Object object1,
final Object object2) {
return object1 == object2;
}
}
public static class EqualityEquals
implements
ObjectComparator {
private static final long serialVersionUID = 510l;
public static ObjectComparator INSTANCE = new EqualityEquals();
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
}
public void writeExternal(ObjectOutput out) throws IOException {
}
public static ObjectComparator getInstance() {
return EqualityEquals.INSTANCE;
}
public int hashCodeOf(final Object key) {
return rehash( key.hashCode() );
}
public int rehash(int h) {
h += ~(h << 9);
h ^= (h >>> 14);
h += (h << 4);
h ^= (h >>> 10);
return h;
}
public EqualityEquals() {
}
public boolean equal(final Object object1,
final Object object2) {
if ( object1 == null ) {
return object2 == null;
}
return object1.equals( object2 );
}
}
public static class FieldIndex
implements
Externalizable {
private static final long serialVersionUID = 510l;
InternalReadAccessor extractor;
Declaration declaration;
public Evaluator evaluator;
public FieldIndex() {
}
public FieldIndex(final InternalReadAccessor extractor,
final Declaration declaration,
final Evaluator evaluator) {
super();
this.extractor = extractor;
this.declaration = declaration;
this.evaluator = evaluator;
}
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
extractor = (InternalReadAccessor) in.readObject();
declaration = (Declaration) in.readObject();
evaluator = (Evaluator) in.readObject();
}
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject( extractor );
out.writeObject( declaration );
out.writeObject( evaluator );
}
public Declaration getDeclaration() {
return this.declaration;
}
public ReadAccessor getExtractor() {
return this.extractor;
}
public Evaluator getEvaluator() {
return this.evaluator;
}
}
public static interface Index
extends
Externalizable {
public FieldIndex getFieldIndex(int index);
public int hashCodeOf(LeftTuple tuple);
public int hashCodeOf(Object object);
public boolean equal(Object object,
LeftTuple tuple);
public boolean equal(LeftTuple tuple1,
LeftTuple tuple2);
public boolean equal(Object object1,
Object object2);
}
public static class SingleIndex
implements
Index {
private static final long serialVersionUID = 510l;
private InternalReadAccessor extractor;
private Declaration declaration;
private Evaluator evaluator;
private int startResult;
public SingleIndex() {
}
public SingleIndex(final FieldIndex[] indexes,
final int startResult) {
this.startResult = startResult;
this.extractor = indexes[0].extractor;
this.declaration = indexes[0].declaration;
this.evaluator = indexes[0].evaluator;
}
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
extractor = (InternalReadAccessor) in.readObject();
declaration = (Declaration) in.readObject();
evaluator = (Evaluator) in.readObject();
startResult = in.readInt();
}
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject( extractor );
out.writeObject( declaration );
out.writeObject( evaluator );
out.writeInt( startResult );
}
public FieldIndex getFieldIndex(int index) {
if ( index > 0 ) {
throw new IllegalArgumentException( "Index position " + index + " does not exist" );
}
return new FieldIndex( extractor,
declaration,
evaluator );
}
public int hashCodeOf(final Object object) {
int hashCode = this.startResult;
hashCode = LeftTupleIndexHashTable.PRIME * hashCode + this.extractor.getHashCode( null,
object );
return rehash( hashCode );
}
public int hashCodeOf(final LeftTuple tuple) {
int hashCode = this.startResult;
hashCode = LeftTupleIndexHashTable.PRIME * hashCode + this.declaration.getHashCode( null,
tuple.get( this.declaration ).getObject() );
return rehash( hashCode );
}
public boolean equal(final Object right,
final LeftTuple tuple) {
final Object left = tuple.get( this.declaration ).getObject();
return this.evaluator.evaluate( null,
this.declaration.getExtractor(),
left,
this.extractor,
right );
}
public boolean equal(final Object object1,
final Object object2) {
return this.evaluator.evaluate( null,
this.extractor,
object1,
this.extractor,
object2 );
}
public boolean equal(final LeftTuple tuple1,
final LeftTuple tuple2) {
final Object object1 = tuple1.get( this.declaration ).getObject();
final Object object2 = tuple2.get( this.declaration ).getObject();
return this.evaluator.evaluate( null,
this.declaration.getExtractor(),
object1,
this.declaration.getExtractor(),
object2 );
}
public int rehash(int h) {
h += ~(h << 9);
h ^= (h >>> 14);
h += (h << 4);
h ^= (h >>> 10);
return h;
}
}
public static class DoubleCompositeIndex
implements
Index {
private static final long serialVersionUID = 510l;
private FieldIndex index0;
private FieldIndex index1;
private int startResult;
public DoubleCompositeIndex() {
}
public DoubleCompositeIndex(final FieldIndex[] indexes,
final int startResult) {
this.startResult = startResult;
this.index0 = indexes[0];
this.index1 = indexes[1];
}
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
index0 = (FieldIndex) in.readObject();
index1 = (FieldIndex) in.readObject();
startResult = in.readInt();
}
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject( index0 );
out.writeObject( index1 );
out.writeInt( startResult );
}
public FieldIndex getFieldIndex(int index) {
switch ( index ) {
case 0 :
return index0;
case 1 :
return index1;
default :
throw new IllegalArgumentException( "Index position " + index + " does not exist" );
}
}
public int hashCodeOf(final Object object) {
int hashCode = this.startResult;
hashCode = LeftTupleIndexHashTable.PRIME * hashCode + this.index0.extractor.getHashCode( null,
object );
hashCode = LeftTupleIndexHashTable.PRIME * hashCode + this.index1.extractor.getHashCode( null,
object );
return rehash( hashCode );
}
public int hashCodeOf(final LeftTuple tuple) {
int hashCode = this.startResult;
hashCode = LeftTupleIndexHashTable.PRIME * hashCode + this.index0.declaration.getHashCode( null,
tuple.get( this.index0.declaration ).getObject() );
hashCode = LeftTupleIndexHashTable.PRIME * hashCode + this.index1.declaration.getHashCode( null,
tuple.get( this.index1.declaration ).getObject() );
return rehash( hashCode );
}
public boolean equal(final Object right,
final LeftTuple tuple) {
final Object left1 = tuple.get( this.index0.declaration ).getObject();
final Object left2 = tuple.get( this.index1.declaration ).getObject();
return this.index0.evaluator.evaluate( null,
this.index0.declaration.getExtractor(),
left1,
this.index0.extractor,
right ) && this.index1.evaluator.evaluate( null,
this.index1.declaration.getExtractor(),
left2,
this.index1.extractor,
right );
}
public boolean equal(final LeftTuple tuple1,
final LeftTuple tuple2) {
final Object object11 = tuple1.get( this.index0.declaration ).getObject();
final Object object12 = tuple2.get( this.index0.declaration ).getObject();
final Object object21 = tuple1.get( this.index1.declaration ).getObject();
final Object object22 = tuple2.get( this.index1.declaration ).getObject();
return this.index0.evaluator.evaluate( null,
this.index0.declaration.getExtractor(),
object11,
this.index0.declaration.getExtractor(),
object12 ) && this.index1.evaluator.evaluate( null,
this.index1.declaration.getExtractor(),
object21,
this.index1.declaration.getExtractor(),
object22 );
}
public boolean equal(final Object object1,
final Object object2) {
return this.index0.evaluator.evaluate( null,
this.index0.extractor,
object1,
this.index0.extractor,
object2 ) && this.index1.evaluator.evaluate( null,
this.index1.extractor,
object1,
this.index1.extractor,
object2 );
}
public int rehash(int h) {
h += ~(h << 9);
h ^= (h >>> 14);
h += (h << 4);
h ^= (h >>> 10);
return h;
}
}
public static class TripleCompositeIndex
implements
Index {
private static final long serialVersionUID = 510l;
private FieldIndex index0;
private FieldIndex index1;
private FieldIndex index2;
private int startResult;
public TripleCompositeIndex() {
}
public TripleCompositeIndex(final FieldIndex[] indexes,
final int startResult) {
this.startResult = startResult;
this.index0 = indexes[0];
this.index1 = indexes[1];
this.index2 = indexes[2];
}
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
index0 = (FieldIndex) in.readObject();
index1 = (FieldIndex) in.readObject();
index2 = (FieldIndex) in.readObject();
startResult = in.readInt();
}
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject( index0 );
out.writeObject( index1 );
out.writeObject( index2 );
out.writeInt( startResult );
}
public FieldIndex getFieldIndex(int index) {
switch ( index ) {
case 0 :
return index0;
case 1 :
return index1;
case 2 :
return index2;
default :
throw new IllegalArgumentException( "Index position " + index + " does not exist" );
}
}
public int hashCodeOf(final Object object) {
int hashCode = this.startResult;
hashCode = LeftTupleIndexHashTable.PRIME * hashCode + this.index0.extractor.getHashCode( null,
object );;
hashCode = LeftTupleIndexHashTable.PRIME * hashCode + this.index1.extractor.getHashCode( null,
object );;
hashCode = LeftTupleIndexHashTable.PRIME * hashCode + this.index2.extractor.getHashCode( null,
object );;
return rehash( hashCode );
}
public int hashCodeOf(final LeftTuple tuple) {
int hashCode = this.startResult;
hashCode = LeftTupleIndexHashTable.PRIME * hashCode + this.index0.declaration.getHashCode( null,
tuple.get( this.index0.declaration ).getObject() );
hashCode = LeftTupleIndexHashTable.PRIME * hashCode + this.index1.declaration.getHashCode( null,
tuple.get( this.index1.declaration ).getObject() );
hashCode = LeftTupleIndexHashTable.PRIME * hashCode + this.index2.declaration.getHashCode( null,
tuple.get( this.index2.declaration ).getObject() );
return rehash( hashCode );
}
public boolean equal(final Object right,
final LeftTuple tuple) {
final Object left1 = tuple.get( this.index0.declaration ).getObject();
final Object left2 = tuple.get( this.index1.declaration ).getObject();
final Object left3 = tuple.get( this.index2.declaration ).getObject();
return this.index0.evaluator.evaluate( null,
this.index0.declaration.getExtractor(),
left1,
this.index0.extractor,
right ) && this.index1.evaluator.evaluate( null,
this.index1.declaration.getExtractor(),
left2,
this.index1.extractor,
right ) && this.index2.evaluator.evaluate( null,
this.index2.declaration.getExtractor(),
left3,
this.index2.extractor,
right );
}
public boolean equal(final LeftTuple tuple1,
final LeftTuple tuple2) {
final Object object11 = tuple1.get( this.index0.declaration ).getObject();
final Object object12 = tuple2.get( this.index0.declaration ).getObject();
final Object object21 = tuple1.get( this.index1.declaration ).getObject();
final Object object22 = tuple2.get( this.index1.declaration ).getObject();
final Object object31 = tuple1.get( this.index2.declaration ).getObject();
final Object object32 = tuple2.get( this.index2.declaration ).getObject();
return this.index0.evaluator.evaluate( null,
this.index0.declaration.getExtractor(),
object11,
this.index0.declaration.getExtractor(),
object12 ) && this.index1.evaluator.evaluate( null,
this.index1.declaration.getExtractor(),
object21,
this.index1.declaration.getExtractor(),
object22 ) && this.index2.evaluator.evaluate( null,
this.index2.declaration.getExtractor(),
object31,
this.index2.declaration.getExtractor(),
object32 );
}
public boolean equal(final Object object1,
final Object object2) {
return this.index0.evaluator.evaluate( null,
this.index0.extractor,
object1,
this.index0.extractor,
object2 ) && this.index1.evaluator.evaluate( null,
this.index1.extractor,
object1,
this.index1.extractor,
object2 ) && this.index2.evaluator.evaluate( null,
this.index2.extractor,
object1,
this.index2.extractor,
object2 );
}
public int rehash(int h) {
h += ~(h << 9);
h ^= (h >>> 14);
h += (h << 4);
h ^= (h >>> 10);
return h;
}
}
}