org.basex.query.value.ValueBuilder Maven / Gradle / Ivy
package org.basex.query.value;
import java.util.*;
import org.basex.query.*;
import org.basex.query.expr.*;
import org.basex.query.value.item.*;
import org.basex.query.value.seq.*;
import org.basex.query.value.seq.tree.*;
import org.basex.query.value.type.*;
import org.basex.util.*;
/**
* A builder for efficiently creating a {@link Value} by prepending and appending
* {@link Item}s and {@link Value}s.
*
* @author BaseX Team 2005-22, BSD License
* @author Leo Woerteler
*/
public final class ValueBuilder {
/** QueryContext. */
private final QueryContext qc;
/** The first added value is cached. */
private Value firstValue;
/** Underlying sequence builder, only instantiated if there are at least two items. */
private TreeSeqBuilder builder;
/**
* Constructor.
* @param qc query context (required for interrupting running queries)
*/
public ValueBuilder(final QueryContext qc) {
this.qc = qc;
}
/**
* Constructor with initial items.
* @param qc query context (required for interrupting running queries)
* @param item1 first item to append
* @param item2 second item to append
*/
public ValueBuilder(final QueryContext qc, final Item item1, final Item item2) {
this(qc);
builder = new TreeSeqBuilder().add(item1).add(item2);
}
/**
* Concatenates two values.
* @param value1 first value to concatenate
* @param value2 second value to concatenate
* @param qc query context
* @return concatenated values
*/
public static Value concat(final Value value1, final Value value2, final QueryContext qc) {
// return existing values
final long size1 = value1.size();
if(size1 == 0) return value2;
final long size2 = value2.size();
if(size2 == 0) return value1;
// prepend or append values
if(size1 > 1) return ((Seq) value1).insertBefore(size1, value2, qc);
if(size2 > 1) return ((Seq) value2).insert(0, (Item) value1, qc);
// concatenate single items
return TreeSeqBuilder.concat((Item) value1, (Item) value2);
}
/**
* Adds an item to the front of the built value.
* @param item item to add
* @return reference to this builder for convenience
*/
public ValueBuilder addFront(final Item item) {
qc.checkStop();
final TreeSeqBuilder tree = builder;
if(tree != null) {
tree.addFront(item);
} else {
final Value first = firstValue;
if(first != null) {
builder = new TreeSeqBuilder().add(first, qc).addFront(item);
firstValue = null;
} else {
firstValue = item;
}
}
return this;
}
/**
* Appends an item to the built value.
* @param item item to append
* @return reference to this builder for convenience
*/
public ValueBuilder add(final Item item) {
qc.checkStop();
final TreeSeqBuilder tree = builder;
if(tree != null) {
tree.add(item);
} else {
final Value first = firstValue;
if(first != null) {
builder = new TreeSeqBuilder().add(first, qc).add(item);
firstValue = null;
} else {
firstValue = item;
}
}
return this;
}
/**
* Appends a value to the built value.
* @param value value to append
* @return reference to this builder for convenience
*/
public ValueBuilder add(final Value value) {
if(value.isEmpty()) {
qc.checkStop();
return this;
}
final TreeSeqBuilder tree = builder;
if(tree != null) {
tree.add(value, qc);
} else {
final Value first = firstValue;
if(first != null) {
builder = new TreeSeqBuilder().add(first, qc).add(value, qc);
firstValue = null;
} else {
firstValue = value;
}
}
return this;
}
/**
* Returns a {@link Value} representation of the items currently stored in this builder.
* @return value
*/
public Value value() {
return value(AtomType.ITEM);
}
/**
* Returns a {@link Value} representation of the items currently stored in this builder
* annotated with the given item type.
* @param type type (only considered if new sequence is created)
* @return value
*/
public Value value(final Type type) {
final Value first = firstValue;
if(first != null) return first;
final TreeSeqBuilder tree = builder;
return tree != null ? tree.sequence(type) : Empty.VALUE;
}
/**
* Returns a {@link Value} representation of the items currently stored in this builder
* annotated with the type of the given expression.
* @param expr expression that created the value (can be {@code null})
* @return value
*/
public Value value(final Expr expr) {
return expr != null ? value(expr.seqType().type) : value();
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder(Util.className(this)).append('[');
final Iterator- iter = firstValue != null ? firstValue.iterator() :
builder != null ? builder.iterator() : Collections.emptyIterator();
if(iter.hasNext()) {
sb.append(iter.next());
while(iter.hasNext()) sb.append(", ").append(iter.next());
}
return sb.append(']').toString();
}
}