/* * Copyright 2015 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * * 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.index; import org.drools.core.reteoo.TupleMemory; import org.drools.core.spi.Tuple; import org.drools.core.util.AbstractHashTable.FieldIndex; import org.drools.core.util.Entry; import org.drools.core.util.FastIterator; import org.drools.core.util.Iterator; import org.drools.core.util.RBTree; import org.drools.core.util.index.IndexUtil.ConstraintType; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.ArrayList; import java.util.List; public class RightTupleIndexRangeRBTree implements TupleMemory, Externalizable { private RBTree<Comparable<Comparable>, TupleList> tree; private FieldIndex ascendingIndex; private ConstraintType ascendingConstraintType; private FieldIndex descendingIndex; private ConstraintType descendingConstraintType; private RightTupleBoundedFastIterator rightTupleBoundedFastIterator; private int size; public RightTupleIndexRangeRBTree() { // constructor for serialisation } public RightTupleIndexRangeRBTree(ConstraintType ascendingConstraintType, FieldIndex ascendingIndex, ConstraintType descendingConstraintType, FieldIndex descendingIndex) { this.ascendingIndex = ascendingIndex; this.ascendingConstraintType = ascendingConstraintType; this.descendingIndex = descendingIndex; this.descendingConstraintType = descendingConstraintType; tree = new RBTree<Comparable<Comparable>, TupleList>(); } public void writeExternal(ObjectOutput out) throws IOException { out.writeObject( tree ); out.writeObject( ascendingIndex ); out.writeObject( ascendingConstraintType ); out.writeObject( descendingIndex ); out.writeObject( descendingConstraintType ); out.writeInt(size); } public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { tree = (RBTree<Comparable<Comparable>, TupleList>) in.readObject(); ascendingIndex = (FieldIndex) in.readObject(); ascendingConstraintType = (ConstraintType) in.readObject(); descendingIndex = (FieldIndex) in.readObject(); descendingConstraintType = (ConstraintType) in.readObject(); size = in.readInt(); } public void add(Tuple tuple) { Comparable key = getRightIndexedValue(tuple); TupleList list = tree.lookup(key); if (list == null) { list = new TupleList(); tree.insert(key, list); } list.add(tuple); size++; } public void remove(Tuple tuple) { tuple.getMemory().remove(tuple); size--; } public void removeAdd(Tuple tuple) { remove(tuple); add(tuple); } public boolean isIndexed() { return true; } public int size() { return size; } public Entry[] toArray() { FastIterator it = tree.fastIterator(); if (it == null) { return new Entry[0]; } List<Comparable> toBeRemoved = new ArrayList<Comparable>(); List<Tuple> result = new ArrayList<Tuple>(); RBTree.Node<Comparable<Comparable>, TupleList> node; while ( (node = (RBTree.Node<Comparable<Comparable>, TupleList>) it.next( null )) != null ) { TupleList bucket = node.value; if (bucket.size() == 0) { toBeRemoved.add(node.key); } else { Tuple entry = bucket.getFirst(); while (entry != null) { result.add(entry); entry = (Tuple) entry.getNext(); } } } for (Comparable key : toBeRemoved) { tree.delete(key); } return result.toArray(new Tuple[result.size()]); } public Tuple getFirst(Tuple leftTuple) { Comparable lowerBound = getLeftAscendingIndexedValue(leftTuple); Tuple rightTuple = getNext(lowerBound, true); return rightTuple == null ? null : checkUpperBound(rightTuple, getLeftDescendingIndexedValue(leftTuple)); } private Tuple checkUpperBound(Tuple rightTuple, Comparable upperBound) { int compResult = getRightIndexedValue(rightTuple).compareTo(upperBound); return compResult < 0 || (compResult == 0 && descendingConstraintType == ConstraintType.LESS_OR_EQUAL) ? rightTuple : null; } public Iterator iterator() { TupleList list = tree.first().value; Tuple firstTuple = list != null ? list.getFirst() : null; return new FastIterator.IteratorAdapter(fastIterator(), firstTuple); } public boolean contains(Tuple tuple) { Comparable key = getRightIndexedValue(tuple); return tree.lookup(key) != null; } public FastIterator fastIterator() { if ( rightTupleBoundedFastIterator != null ) { rightTupleBoundedFastIterator = new RightTupleBoundedFastIterator(); } return rightTupleBoundedFastIterator; } public FastIterator fullFastIterator() { if ( rightTupleBoundedFastIterator != null ) { rightTupleBoundedFastIterator = new RightTupleBoundedFastIterator(); } return rightTupleBoundedFastIterator; } public FastIterator fullFastIterator(Tuple tuple) { FastIterator fastIterator = fullFastIterator(); Comparable key = getRightIndexedValue(tuple); fastIterator.next(getNext(key, true)); return fastIterator; } public IndexType getIndexType() { return IndexType.COMPARISON; } private Tuple getNext(Comparable lowerBound, boolean first) { RBTree.Node<Comparable<Comparable>, TupleList> firstNode; while (true) { switch (ascendingConstraintType) { case GREATER_THAN: firstNode = tree.findNearestNode(lowerBound, false, RBTree.Boundary.LOWER); break; case GREATER_OR_EQUAL: firstNode = tree.findNearestNode(lowerBound, first, RBTree.Boundary.LOWER); break; default: throw new UnsupportedOperationException("Cannot call remove constraint of type: " + ascendingConstraintType); } if (firstNode != null && firstNode.value.size() == 0) { tree.delete(firstNode.key); } else { break; } } return firstNode == null ? null : firstNode.value.getFirst(); } private Comparable getLeftAscendingIndexedValue(Tuple leftTuple) { return (Comparable) ascendingIndex.getDeclaration().getExtractor().getValue(leftTuple.get(ascendingIndex.getDeclaration()).getObject()); } private Comparable getLeftDescendingIndexedValue(Tuple leftTuple) { return (Comparable) descendingIndex.getDeclaration().getExtractor().getValue(leftTuple.get(descendingIndex.getDeclaration()).getObject()); } private Comparable getRightIndexedValue(Tuple rightTuple) { return (Comparable) ascendingIndex.getExtractor().getValue( rightTuple.getFactHandle().getObject() ); } public class RightTupleBoundedFastIterator implements FastIterator { private Comparable upperBound; public void setUpperBound(Tuple leftTuple) { upperBound = getLeftDescendingIndexedValue(leftTuple); } public Entry next(Entry object) { if (object == null) { return null; } Tuple rightTuple = (Tuple) object; Tuple next = (Tuple) rightTuple.getNext(); if (next != null) { return next; } Comparable key = getRightIndexedValue(rightTuple); next = getNext(key, false); return next == null ? null : checkUpperBound(next, upperBound); } public boolean isFullIterator() { return false; } } public void clear() { tree = new RBTree<Comparable<Comparable>, TupleList>(); } }