Skip to content

Commit 4817250

Browse files
[MOD] Range, arithmetic expressions: pre-compute size
1 parent 1cea00c commit 4817250

File tree

3 files changed

+31
-11
lines changed

3 files changed

+31
-11
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public static Expr get(final Expr positions, final OpV op, final InputInfo info,
6060
return IntPos.get(rs.min(), rs.max(), info);
6161
}
6262
// range. example: position() = 3 to $max
63-
if(pos instanceof final Range rng && rng.ints) {
63+
if(pos instanceof final Range rng && rng.integers()) {
6464
if(pos.isSimple()) return new SimplePos(info, pos.args());
6565
return ref instanceof Pos ? null : new Pos(info, pos);
6666
}

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

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@
2727
public final class Range extends Arr {
2828
/** Dummy value for representing the last item in a sequence. */
2929
private static final long LAST = 1L << 52;
30-
/** Expressions yield integers. */
31-
boolean ints;
3230

3331
/**
3432
* Constructor.
@@ -48,16 +46,36 @@ public Expr optimize(final CompileContext cc) throws QueryException {
4846
if(values(false, cc)) return cc.preEval(this);
4947

5048
final Expr min = exprs[0], max = exprs[1];
51-
final SeqType st1 = min.seqType(), st2 = max.seqType();
52-
ints = st1.instanceOf(Types.INTEGER_O) && st2.instanceOf(Types.INTEGER_O);
53-
if(min.equals(max)) {
54-
exprType.assign(Occ.EXACTLY_ONE);
55-
if(ints && !min.has(Flag.NDT)) expr = min;
49+
if(!min.has(Flag.NDT)) {
50+
if(min.equals(max)) {
51+
// identical operands: $int to $int
52+
exprType.assign(Occ.EXACTLY_ONE);
53+
if(integers()) expr = min;
54+
} else if(max instanceof Arith arith && min.equals(max.arg(0))) {
55+
if(arith.calc.oneOf(Calc.ADD, Calc.SUBTRACT) && arith.arg(1) instanceof Itr itr) {
56+
// known result size: . to . + 10
57+
final long n = (arith.calc == Calc.ADD ? itr.itr() : -itr.itr()) + 1;
58+
if(n < 1) {
59+
expr = Empty.VALUE;
60+
} else {
61+
exprType.assign(seqType(), n);
62+
}
63+
}
64+
}
5665
}
5766
}
5867
return cc.replaceWith(this, expr);
5968
}
6069

70+
/**
71+
* Indicates if the range operands are known to return single integers.
72+
* @return result of check
73+
*/
74+
boolean integers() {
75+
final SeqType st1 = exprs[0].seqType(), st2 = exprs[1].seqType();
76+
return st1.instanceOf(Types.INTEGER_O) && st2.instanceOf(Types.INTEGER_O);
77+
}
78+
6179
@Override
6280
public Value value(final QueryContext qc) throws QueryException {
6381
final Item min = exprs[0].atomItem(qc, info);
@@ -75,9 +93,7 @@ public Value value(final QueryContext qc) throws QueryException {
7593

7694
@Override
7795
public Range copy(final CompileContext cc, final IntObjectMap<Var> vm) {
78-
final Range r = copyType(new Range(info, copyAll(cc, vm, exprs)));
79-
r.ints = ints;
80-
return r;
96+
return copyType(new Range(info, copyAll(cc, vm, exprs)));
8197
}
8298

8399
@Override

basex-core/src/test/java/org/basex/query/simple/SimpleTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,10 @@ public final class SimpleTest extends QueryTest {
308308
"let $a := <a/> " +
309309
"let $b := (# db:copynode false #) { <_>{ $a }</_> } " +
310310
"return $b/a is $a" },
311+
312+
{ "Range 1", integers(100), "count((1 to 10) ! (. to . + 9))" },
313+
{ "Range 2", integers(100), "count((1 to 10) ! (. to . - -9))" },
314+
{ "Range 3", integers(1_000_000_000), "count((1 to 100_000) ! (. to . + 9_999))" },
311315
};
312316
}
313317
}

0 commit comments

Comments
 (0)