package org.basex.query.item; import static org.basex.query.QueryText.*; import static org.basex.query.util.Err.*; import java.io.IOException; import java.io.InputStream; import java.math.BigDecimal; import org.basex.io.in.ArrayInput; import org.basex.io.serial.Serializer; import org.basex.query.QueryContext; import org.basex.query.QueryException; import org.basex.query.iter.ValueIter; import org.basex.util.InputInfo; import org.basex.util.Token; import org.basex.util.Util; /** * Abstract item. * * @author BaseX Team 2005-12, BSD License * @author Christian Gruen */ public abstract class Item extends Value { /** Undefined item. */ public static final int UNDEF = Integer.MIN_VALUE; /** Score value. Will be {@code null} if not assigned. */ Double score; /** * Constructor. * @param t data type */ Item(final Type t) { super(t); } @Override public final ValueIter iter() { return new ItemIter(this); } @Override public final Item item(final QueryContext ctx, final InputInfo ii) { return this; } @Override public final Item itemAt(final long pos) { return this; } @Override public final Item ebv(final QueryContext ctx, final InputInfo ii) { return this; } @Override public final Item test(final QueryContext ctx, final InputInfo ii) throws QueryException { return bool(ii) ? this : null; } @Override public final boolean isItem() { return true; } /** * Returns a string representation of the value. * @param ii input info, use {@code null} if none is available * @return string value * @throws QueryException if the item can't be atomized */ public abstract byte[] string(final InputInfo ii) throws QueryException; /** * Returns a boolean representation of the value. * @param ii input info * @return boolean value * @throws QueryException query exception */ public boolean bool(final InputInfo ii) throws QueryException { throw CONDTYPE.thrw(ii, type, this); } /** * Returns a decimal representation of the value. * @param ii input info * @return decimal value * @throws QueryException query exception */ public BigDecimal dec(final InputInfo ii) throws QueryException { return Dec.parse(string(ii), ii); } /** * Returns an integer (long) representation of the value. * @param ii input info * @return long value * @throws QueryException query exception */ public long itr(final InputInfo ii) throws QueryException { return Int.parse(string(ii), ii); } /** * Returns a float representation of the value. * @param ii input info * @return float value * @throws QueryException query exception */ public float flt(final InputInfo ii) throws QueryException { return Flt.parse(string(ii), ii); } /** * Returns a double representation of the value. * @param ii input info * @return double value * @throws QueryException query exception */ public double dbl(final InputInfo ii) throws QueryException { return Dbl.parse(string(ii), ii); } /** * Checks if the items can be compared. * @param it item to be compared * @return result of check */ public final boolean comparable(final Item it) { final Type t1 = type; final Type t2 = it.type; return t1 == t2 || t1.isNumber() && t2.isNumber() || (t1.isUntyped() || t1.isString()) && (t2.isUntyped() || t2.isString()) || t1.isDuration() && t2.isDuration(); } /** * Checks the items for equality. * @param ii input info * @param it item to be compared * @return result of check * @throws QueryException query exception */ public abstract boolean eq(final InputInfo ii, final Item it) throws QueryException; /** * Checks the items for equivalence. * @param ii input info * @param it item to be compared * @return result of check * @throws QueryException query exception */ public final boolean equiv(final InputInfo ii, final Item it) throws QueryException { // check if both values are NaN, or if values are equal.. return (this == Dbl.NAN || this == Flt.NAN) && it.type.isNumber() && Double.isNaN(it.dbl(ii)) || comparable(it) && eq(ii, it); } /** * Returns the difference between the current and the specified item. * @param ii input info * @param it item to be compared * @return difference * @throws QueryException query exception */ public int diff(final InputInfo ii, final Item it) throws QueryException { throw (this == it ? TYPECMP : XPTYPECMP).thrw(ii, type, it.type); } /** * Returns an input stream. * @param ii input info * @return input stream * @throws QueryException query exception */ public InputStream input(final InputInfo ii) throws QueryException { return new ArrayInput(string(ii)); } @Override public final SeqType type() { return type.seqType(); } @Override public final long size() { return 1; } @Override public final boolean iterable() { return true; } /** * Returns a score value. * @return score value */ public double score() { return score == null ? 0 : score; } /** * Sets a new score value. * @param s score value */ public final void score(final double s) { if(score != null || s != 0) score = s; } /** * Serializes the item. * @param ser serializer * @throws IOException I/O exception */ public void serialize(final Serializer ser) throws IOException { // this method is overwritten by some data types ser.item(this); } /** * Throws a cast error. * @param val cast value * @param ii input info * @return never * @throws QueryException query exception */ final QueryException castErr(final Object val, final InputInfo ii) throws QueryException { return FUNCAST.thrw(ii, type, val); } /** * Throws a date format exception. * @param i input * @param ex example format * @param ii input info * @return never * @throws QueryException query exception */ final QueryException dateErr(final byte[] i, final String ex, final InputInfo ii) throws QueryException { throw DATEFORMAT.thrw(ii, type, i, ex); } @Override public void plan(final Serializer ser) throws IOException { try { ser.emptyElement(ITM, VAL, string(null), TYP, Token.token(info())); } catch(final QueryException ex) { // only function items throw exceptions in atomization, and they should // override plan(Serializer) sensibly Util.notexpected(ex); } } @Override public int hash(final InputInfo ii) throws QueryException { return Token.hash(string(ii)); } @Override public final int writeTo(final Item[] arr, final int start) { arr[start] = this; return 1; } @Override public final boolean homogenous() { return true; } /** * Item iterator. * @author BaseX Team 2005-12, BSD License * @author Christian Gruen */ private static final class ItemIter extends ValueIter { /** Item. */ private final Item item; /** Requested flag. */ private boolean req; /** * Constructor. * @param it item */ ItemIter(final Item it) { item = it; } @Override public Item next() { if(req) return null; req = true; return item; } @Override public long size() { return 1; } @Override public Item get(final long i) { return item; } @Override public boolean reset() { req = false; return true; } @Override public Value value() { return item; } } }