Skip to content

Commit 7c0ced0

Browse files
[MOD] Sequence/Array builders: optimizations
1 parent 760763b commit 7c0ced0

29 files changed

+206
-174
lines changed

basex-core/src/main/java/org/basex/query/expr/List.java

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -201,13 +201,20 @@ private Iter iter(final int i) throws QueryException {
201201

202202
@Override
203203
public Value value(final QueryContext qc) throws QueryException {
204-
// special case: concatenate two sequences
205-
if(exprs.length == 2) return exprs[0].value(qc).append(exprs[1].value(qc), qc);
206-
207-
// general case: concatenate all sequences (unknown size: do not create compact data structures)
208-
final ValueBuilder vb = new ValueBuilder(qc, size() != -1 ? size() : Integer.MIN_VALUE);
209-
for(final Expr expr : exprs) vb.add(expr.value(qc));
210-
return vb.value(this);
204+
// known result size: use builders with optimized data structures
205+
final long size = size();
206+
if(size != -1) {
207+
final ValueBuilder vb = new ValueBuilder(qc, size);
208+
for(final Expr expr : exprs) vb.add(expr.value(qc));
209+
return vb.value(this);
210+
}
211+
// otherwise, append values (uses tree structure)
212+
Value value = null;
213+
for(final Expr expr : exprs) {
214+
final Value v = expr.value(qc);
215+
value = value != null ? value.append(v, qc) : v;
216+
}
217+
return value;
211218
}
212219

213220
@Override

basex-core/src/main/java/org/basex/query/func/array/ArrayPut.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public XQArray item(final QueryContext qc, final InputInfo ii) throws QueryExcep
1919
final XQArray array = toArray(arg(0), qc);
2020
final long position = toLong(arg(1), qc);
2121
final Value member = arg(2).value(qc);
22-
return array.put(toPos(array, position, false), member);
22+
return array.putMember(toPos(array, position, false), member, qc);
2323
}
2424

2525
@Override

basex-core/src/main/java/org/basex/query/func/fn/FnInsertSeparator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public final Value value(final QueryContext qc) throws QueryException {
2121
final Iter input = arg(0).iter(qc);
2222
final Value separator = arg(1).value(qc);
2323

24-
final ValueBuilder vb = new ValueBuilder(qc);
24+
final ValueBuilder vb = new ValueBuilder(qc, size());
2525
Item item = input.next();
2626
if(item != null) {
2727
vb.add(item);

basex-core/src/main/java/org/basex/query/func/fn/PlanFn.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,7 @@ private XQMap record(final ANode node, final Plan plan, final QueryContext qc)
470470
private XQArray mixed(final ANode node, final ANode parent, final Plan plan,
471471
final QueryContext qc, final boolean ignoreEmpty) throws QueryException {
472472

473-
final ArrayBuilder ab = new ArrayBuilder();
473+
final ArrayBuilder ab = new ArrayBuilder(qc);
474474
for(final ANode attr : children(NodeType.ATTRIBUTE, node)) {
475475
ab.add(new MapBuilder().put(nodeName(attr, node, plan, qc), attr.string()).map());
476476
}

basex-core/src/main/java/org/basex/query/value/Value.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,8 @@ public final Value insert(final long pos, final Value value, final QueryContext
165165

166166
/**
167167
* Removes an item at the given position.
168-
* @param pos deletion position, must be between 0 and {@link #size()} - 1
168+
* @param pos deletion position, must be greater than 0 and smaller than {@link #size()} - 1
169+
* (use {@link #subSeq(long, long, QueryContext)} to remove first or last item)
169170
* @param qc query context
170171
* @return new sequence
171172
*/

basex-core/src/main/java/org/basex/query/value/ValueBuilder.java

Lines changed: 44 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import org.basex.query.*;
44
import org.basex.query.expr.*;
5+
import org.basex.query.util.list.*;
56
import org.basex.query.value.item.*;
67
import org.basex.query.value.seq.*;
78
import org.basex.query.value.seq.tree.*;
@@ -19,9 +20,9 @@ public final class ValueBuilder {
1920
/** QueryContext. */
2021
private final QueryContext qc;
2122

22-
/** Sequence builder, only instantiated if there are at least two items. */
23-
private SeqBuilder sequence;
24-
/** Capacity ({@link Integer#MIN_VALUE}: create no compact data structures). */
23+
/** Builder, only instantiated if there are at least two items. */
24+
private SeqBuilder builder;
25+
/** Capacity ({@link Long#MIN_VALUE}: create no compact data structures). */
2526
private final long capacity;
2627
/** The first added value is cached. */
2728
private Value single;
@@ -37,7 +38,7 @@ public ValueBuilder(final QueryContext qc) {
3738
/**
3839
* Constructor.
3940
* @param qc query context (required for interrupting running queries)
40-
* @param capacity initial capacity ({@link Integer#MIN_VALUE}: create no compact data structures)
41+
* @param capacity initial capacity ({@link Long#MIN_VALUE}: create no compact data structures)
4142
*/
4243
public ValueBuilder(final QueryContext qc, final long capacity) {
4344
this.qc = qc;
@@ -52,24 +53,23 @@ public ValueBuilder(final QueryContext qc, final long capacity) {
5253
public ValueBuilder add(final Value value) {
5354
if(!value.isEmpty()) {
5455
qc.checkStop();
55-
final Value sngl = single;
56-
if(sngl != null) {
57-
single = null;
58-
if(capacity != Integer.MIN_VALUE) {
59-
sequence = isStr(sngl) && isStr(value) ? new StrSeqBuilder() :
60-
isAtm(sngl) && isAtm(value) ? new AtmSeqBuilder() :
61-
isInt(sngl) && isInt(value) ? new IntSeqBuilder() :
62-
isDbl(sngl) && isDbl(value) ? new DblSeqBuilder() :
63-
isBln(sngl) && isBln(value) ? new BlnSeqBuilder() : null;
56+
if(builder == null) {
57+
final Value sngl = single;
58+
if(sngl == null) {
59+
single = value;
60+
return this;
6461
}
65-
if(sequence == null) sequence = new TreeSeqBuilder();
62+
single = null;
63+
builder = capacity == Long.MIN_VALUE ? new TreeSeqBuilder() :
64+
isStr(sngl) && isStr(value) ? new StrSeqBuilder() :
65+
isAtm(sngl) && isAtm(value) ? new AtmSeqBuilder() :
66+
isInt(sngl) && isInt(value) ? new IntSeqBuilder() :
67+
isDbl(sngl) && isDbl(value) ? new DblSeqBuilder() :
68+
isBln(sngl) && isBln(value) ? new BlnSeqBuilder() :
69+
new ItemSeqBuilder();
6670
add(sngl);
6771
}
68-
if(sequence != null) {
69-
sequence = sequence.add(value, qc);
70-
} else {
71-
single = value;
72-
}
72+
builder = builder.add(value, qc);
7373
}
7474
return this;
7575
}
@@ -90,9 +90,9 @@ public Value value() {
9090
*/
9191
public Value value(final Type type) {
9292
try {
93-
return sequence != null ? sequence.value(type) : single != null ? single : Empty.VALUE;
93+
return builder != null ? builder.value(type) : single != null ? single : Empty.VALUE;
9494
} finally {
95-
sequence = null;
95+
builder = null;
9696
single = null;
9797
}
9898
}
@@ -154,12 +154,12 @@ static boolean isBln(final Value value) {
154154

155155
@Override
156156
public String toString() {
157-
return Util.className(this) + '[' + Util.className(sequence != null ? sequence :
157+
return Util.className(this) + '[' + Util.className(builder != null ? builder :
158158
single != null ? single : Empty.VALUE) + ']';
159159
}
160160

161161
/** String sequence builder. */
162-
final class StrSeqBuilder implements SeqBuilder {
162+
final class StrSeqBuilder extends SeqBuilder {
163163
/** Values. */
164164
private final TokenList values = new TokenList(capacity);
165165

@@ -179,7 +179,7 @@ public Value value(final Type type) {
179179
}
180180

181181
/** Untyped atomic sequence builder. */
182-
final class AtmSeqBuilder implements SeqBuilder {
182+
final class AtmSeqBuilder extends SeqBuilder {
183183
/** Values. */
184184
private final TokenList values = new TokenList(capacity);
185185

@@ -199,7 +199,7 @@ public Value value(final Type type) {
199199
}
200200

201201
/** Integer sequence builder. */
202-
final class IntSeqBuilder implements SeqBuilder {
202+
final class IntSeqBuilder extends SeqBuilder {
203203
/** Values. */
204204
private final IntList values = new IntList(capacity);
205205

@@ -222,7 +222,7 @@ public Value value(final Type type) {
222222
}
223223

224224
/** Double sequence builder. */
225-
final class DblSeqBuilder implements SeqBuilder {
225+
final class DblSeqBuilder extends SeqBuilder {
226226
/** Values. */
227227
private final DoubleList values = new DoubleList(capacity);
228228

@@ -242,7 +242,7 @@ public Value value(final Type type) {
242242
}
243243

244244
/** Boolean sequence builder. */
245-
final class BlnSeqBuilder implements SeqBuilder {
245+
final class BlnSeqBuilder extends SeqBuilder {
246246
/** Values. */
247247
private final BoolList values = new BoolList(capacity);
248248

@@ -260,4 +260,21 @@ public Value value(final Type type) {
260260
return BlnSeq.get(values.finish());
261261
}
262262
}
263+
264+
/** Item sequence builder. */
265+
final class ItemSeqBuilder extends SeqBuilder {
266+
/** Items. */
267+
private final ItemList items = new ItemList(capacity);
268+
269+
@Override
270+
public SeqBuilder add(final Item item) {
271+
items.add(item);
272+
return this;
273+
}
274+
275+
@Override
276+
public Value value(final Type type) {
277+
return items.value(type);
278+
}
279+
}
263280
}

basex-core/src/main/java/org/basex/query/value/array/ArrBuilder.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,23 @@
44
import org.basex.query.value.type.*;
55

66
/**
7-
* An interface for creating sequences.
7+
* Abstract array builder.
88
*
99
* @author BaseX Team, BSD License
1010
* @author Christian Gruen
1111
*/
12-
public interface ArrBuilder {
12+
public abstract class ArrBuilder {
1313
/**
14-
* Adds a member to the end of the sequence.
15-
* @param value value to add
14+
* Appends a member.
15+
* @param value value to append
1616
* @return reference to this builder for convenience
1717
*/
18-
ArrBuilder add(Value value);
18+
abstract ArrBuilder add(Value value);
1919

2020
/**
2121
* Creates an array containing the values of this builder.
2222
* @param type type of all members in this sequence
2323
* @return resulting sequence
2424
*/
25-
XQArray array(ArrayType type);
25+
abstract XQArray array(ArrayType type);
2626
}

basex-core/src/main/java/org/basex/query/value/array/ArrayBuilder.java

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,39 +12,32 @@
1212
* @author Christian Gruen
1313
*/
1414
public final class ArrayBuilder {
15-
/** QueryContext (can be {@code null}). */
15+
/** QueryContext. */
1616
private final QueryContext qc;
1717

18-
/** Sequence builder, only instantiated if there are at least two members. */
19-
private ArrBuilder array;
20-
/** Capacity ({@link Integer#MIN_VALUE}: create no compact data structures). */
18+
/** Builder, only instantiated if there are at least two items. */
19+
private ArrBuilder builder;
20+
/** Capacity ({@link Long#MIN_VALUE}: create no compact data structures). */
2121
private final long capacity;
2222
/** The first added value is cached. */
2323
private Value single;
2424

2525
/**
2626
* Constructor.
27-
*/
28-
public ArrayBuilder() {
29-
this(null);
30-
}
31-
32-
/**
33-
* Constructor.
34-
* @param qc query context (can be {@code null}, required for interrupting running queries)
27+
* @param qc query context (required for interrupting running queries)
3528
*/
3629
public ArrayBuilder(final QueryContext qc) {
3730
this(qc, -1);
3831
}
3932

4033
/**
4134
* Constructor.
42-
* @param qc query context (can be {@code null}, required for interrupting running queries)
43-
* @param capacity initial capacity ({@link Integer#MIN_VALUE}: create no compact data structures)
35+
* @param qc query context (required for interrupting running queries)
36+
* @param capacity initial capacity ({@link Long#MIN_VALUE}: create no compact data structures)
4437
*/
4538
public ArrayBuilder(final QueryContext qc, final long capacity) {
4639
this.qc = qc;
47-
this.capacity = qc != null ? capacity : Integer.MIN_VALUE;
40+
this.capacity = capacity;
4841
}
4942

5043
/**
@@ -53,18 +46,19 @@ public ArrayBuilder(final QueryContext qc, final long capacity) {
5346
* @return reference to this builder for convenience
5447
*/
5548
public ArrayBuilder add(final Value value) {
56-
final Value sngl = single;
57-
if(sngl != null) {
49+
if(builder == null) {
50+
qc.checkStop();
51+
final Value sngl = single;
52+
if(sngl == null) {
53+
single = value;
54+
return this;
55+
}
5856
single = null;
59-
array = capacity != Integer.MIN_VALUE && sngl.size() == 1 && value.size() == 1 ?
60-
new ItemArrayBuilder(qc, capacity) : new TreeArrayBuilder();
57+
builder = capacity == Long.MIN_VALUE || sngl.size() != 1 || value.size() != 1 ?
58+
new TreeArrayBuilder() : new ItemArrayBuilder();
6159
add(sngl);
6260
}
63-
if(array != null) {
64-
array = array.add(value);
65-
} else {
66-
single = value;
67-
}
61+
builder = builder.add(value);
6862
return this;
6963
}
7064

@@ -84,10 +78,10 @@ public XQArray array() {
8478
*/
8579
public XQArray array(final ArrayType type) {
8680
try {
87-
return array != null ? array.array(type) : single != null ? XQArray.get(single) :
81+
return builder != null ? builder.array(type) : single != null ? XQArray.get(single) :
8882
XQArray.empty();
8983
} finally {
90-
array = null;
84+
builder = null;
9185
single = null;
9286
}
9387
}
@@ -100,4 +94,26 @@ public XQArray array(final ArrayType type) {
10094
public XQArray array(final Expr expr) {
10195
return expr != null ? array((ArrayType) expr.seqType().type) : array();
10296
}
97+
98+
/** Item array builder. */
99+
final class ItemArrayBuilder extends ArrBuilder {
100+
/** Value builder. */
101+
private final ValueBuilder vb = new ValueBuilder(qc, capacity);
102+
103+
@Override
104+
public ArrBuilder add(final Value value) {
105+
if(value.size() == 1) {
106+
vb.add(value);
107+
return this;
108+
}
109+
final TreeArrayBuilder ab = new TreeArrayBuilder();
110+
for(final Value member : vb.value()) ab.add(member);
111+
return ab.add(value);
112+
}
113+
114+
@Override
115+
public XQArray array(final ArrayType type) {
116+
return new ItemArray(vb.value(type.valueType().type));
117+
}
118+
}
103119
}

basex-core/src/main/java/org/basex/query/value/array/BigArray.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ public long structSize() {
6868
}
6969

7070
@Override
71-
public XQArray put(final long pos, final Value value) {
71+
public XQArray putMember(final long pos, final Value value, final QueryContext qc) {
72+
qc.checkStop();
7273
final Type tp = union(value);
7374
long p = pos;
7475
final int ll = left.length;

basex-core/src/main/java/org/basex/query/value/array/EmptyArray.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public long structSize() {
3838
}
3939

4040
@Override
41-
public XQArray put(final long pos, final Value value) {
41+
public XQArray putMember(final long pos, final Value value, final QueryContext qc) {
4242
throw Util.notExpected();
4343
}
4444

0 commit comments

Comments
 (0)