001: package prefuse.data.expression;
002:
003: import java.util.Comparator;
004:
005: import prefuse.data.Schema;
006: import prefuse.data.Tuple;
007: import prefuse.util.TypeLib;
008: import prefuse.util.collections.DefaultLiteralComparator;
009: import prefuse.util.collections.LiteralComparator;
010:
011: /**
012: * Predicate instance that evaluates if a value is contained within
013: * a bounded range.
014: *
015: * @author <a href="http://jheer.org">jeffrey heer</a>
016: */
017: public class RangePredicate extends BinaryExpression implements
018: Predicate {
019:
020: /** Indicates the both the left and right bounds are inclusive */
021: public static final int IN_IN = 0;
022: /** Indicates an inclusive left bound and exclusive right bound */
023: public static final int IN_EX = 1;
024: /** Indicates an exclusive left bound and inclusive right bound */
025: public static final int EX_IN = 2;
026: /** Indicates the both the left and right bounds are exclusive */
027: public static final int EX_EX = 3;
028:
029: private Expression m_middle;
030: private Comparator m_cmp;
031:
032: // ------------------------------------------------------------------------
033: // Constructors
034:
035: /**
036: * Create a new RangePredicate. Both bounds are assumed to be inclusive.
037: * @param middle the value to test for membership in the range
038: * @param left the lower range bound
039: * @param right the upper range bound
040: */
041: public RangePredicate(Expression middle, Expression left,
042: Expression right) {
043: this (IN_IN, middle, left, right, DefaultLiteralComparator
044: .getInstance());
045: }
046:
047: /**
048: * Create a new RangePredicate. Both bounds are assumed to be inclusive.
049: * @param middle the value to test for membership in the range
050: * @param left the lower range bound
051: * @param right the upper range bound
052: * @param cmp the comparator to use for comparing data values
053: */
054: public RangePredicate(Expression middle, Expression left,
055: Expression right, Comparator cmp) {
056: this (IN_IN, middle, left, right, cmp);
057: }
058:
059: /**
060: * Create a new RangePredicate.
061: * @param operation operation code indicating the inclusiveness /
062: * exclusiveness of the bounds
063: * @param middle the value to test for membership in the range
064: * @param left the lower range bound
065: * @param right the upper range bound
066: */
067: public RangePredicate(int operation, Expression middle,
068: Expression left, Expression right) {
069: this (operation, middle, left, right, DefaultLiteralComparator
070: .getInstance());
071: }
072:
073: /**
074: * Create a new RangePredicate.
075: * @param operation operation code indicating the inclusiveness /
076: * exclusiveness of the bounds
077: * @param middle the value to test for membership in the range
078: * @param left the lower range bound
079: * @param right the upper range bound
080: * @param cmp the comparator to use for comparing data values
081: */
082: public RangePredicate(int operation, Expression middle,
083: Expression left, Expression right, Comparator cmp) {
084: super (operation, IN_IN, EX_EX, left, right);
085:
086: this .m_middle = middle;
087: this .m_cmp = cmp;
088: }
089:
090: // ------------------------------------------------------------------------
091: // Accessors
092:
093: /**
094: * Get the middle expression being tested for inclusion in the range
095: * @return the middle expression
096: */
097: public Expression getMiddleExpression() {
098: return m_middle;
099: }
100:
101: /**
102: * Get the comparator used to compare data values.
103: * @return the comparator used to compare data values
104: */
105: public Comparator getComparator() {
106: return m_cmp;
107: }
108:
109: // ------------------------------------------------------------------------
110: // Expression Interface
111:
112: /**
113: * @see prefuse.data.expression.Expression#getBoolean(prefuse.data.Tuple)
114: */
115: public boolean getBoolean(Tuple t) {
116: Class lType = m_left.getType(t.getSchema());
117: Class rType = m_right.getType(t.getSchema());
118: Class mType = m_middle.getType(t.getSchema());
119: Class sType = null;
120:
121: // see if we can match the end-points' type
122: if (lType.isAssignableFrom(rType)) {
123: sType = lType;
124: } else if (rType.isAssignableFrom(lType)) {
125: sType = rType;
126: }
127:
128: int c1, c2 = 0;
129: if (sType != null && TypeLib.isNumericType(sType)
130: && TypeLib.isNumericType(mType)) {
131: // the range is of numeric types
132: Class type = TypeLib.getNumericType(sType, mType);
133: if (type == int.class) {
134: int lo = m_left.getInt(t);
135: int hi = m_right.getInt(t);
136: int x = m_middle.getInt(t);
137: c1 = ((LiteralComparator) m_cmp).compare(x, lo);
138: c2 = ((LiteralComparator) m_cmp).compare(x, hi);
139: } else if (type == long.class) {
140: long lo = m_left.getLong(t);
141: long hi = m_right.getLong(t);
142: long x = m_middle.getLong(t);
143: c1 = ((LiteralComparator) m_cmp).compare(x, lo);
144: c2 = ((LiteralComparator) m_cmp).compare(x, hi);
145: } else if (type == float.class) {
146: float lo = m_left.getFloat(t);
147: float hi = m_right.getFloat(t);
148: float x = m_middle.getFloat(t);
149: c1 = ((LiteralComparator) m_cmp).compare(x, lo);
150: c2 = ((LiteralComparator) m_cmp).compare(x, hi);
151: } else if (type == double.class) {
152: double lo = m_left.getDouble(t);
153: double hi = m_right.getDouble(t);
154: double x = m_middle.getDouble(t);
155: c1 = ((LiteralComparator) m_cmp).compare(x, lo);
156: c2 = ((LiteralComparator) m_cmp).compare(x, hi);
157: } else {
158: throw new IllegalStateException();
159: }
160: } else {
161: Object lo = m_left.get(t);
162: Object hi = m_right.get(t);
163: Object x = m_middle.get(t);
164: c1 = m_cmp.compare(x, lo);
165: c2 = m_cmp.compare(x, hi);
166: }
167:
168: // check the comparison values to see if it is in-range
169: switch (m_op) {
170: case IN_IN:
171: return (c1 >= 0 && c2 <= 0);
172: case IN_EX:
173: return (c1 >= 0 && c2 < 0);
174: case EX_IN:
175: return (c1 > 0 && c2 <= 0);
176: case EX_EX:
177: return (c1 > 0 && c2 < 0);
178: default:
179: throw new IllegalStateException("Unknown operation.");
180: }
181: }
182:
183: /**
184: * @see prefuse.data.expression.Expression#getType(prefuse.data.Schema)
185: */
186: public Class getType(Schema s) {
187: return boolean.class;
188: }
189:
190: /**
191: * @see prefuse.data.expression.Expression#get(prefuse.data.Tuple)
192: */
193: public Object get(Tuple t) {
194: return (getBoolean(t) ? Boolean.TRUE : Boolean.FALSE);
195: }
196:
197: /**
198: * @see prefuse.data.expression.Expression#visit(prefuse.data.expression.ExpressionVisitor)
199: */
200: public void visit(ExpressionVisitor v) {
201: v.visitExpression(this );
202: v.down();
203: m_left.visit(v);
204: v.up();
205: v.down();
206: m_middle.visit(v);
207: v.up();
208: v.down();
209: m_right.visit(v);
210: v.up();
211: }
212:
213: /**
214: * @see prefuse.data.expression.AbstractExpression#addChildListeners()
215: */
216: protected void addChildListeners() {
217: super .addChildListeners();
218: m_middle.addExpressionListener(this );
219: }
220:
221: /**
222: * @see prefuse.data.expression.AbstractExpression#removeChildListeners()
223: */
224: protected void removeChildListeners() {
225: super .removeChildListeners();
226: m_middle.removeExpressionListener(this );
227: }
228:
229: /**
230: * @see java.lang.Object#toString()
231: */
232: public String toString() {
233: String lop = "?", rop = "?";
234: switch (m_op) {
235: case IN_IN:
236: lop = rop = "<=";
237: break;
238: case IN_EX:
239: lop = "<=";
240: rop = "<";
241: break;
242: case EX_IN:
243: lop = "<";
244: rop = "<=";
245: break;
246: case EX_EX:
247: lop = rop = "<";
248: break;
249: }
250: return '(' + m_left.toString() + ' ' + lop + ' '
251: + m_middle.toString() + " AND " + m_middle.toString()
252: + ' ' + rop + ' ' + m_right.toString() + ')';
253: }
254:
255: } // end of class RangePredicate
|