Skip to content

Commit 8a8ad7a

Browse files
[MOD] XQuery, revised numeric comparisons: optimizations. qtspecs#2218
1 parent 9d692e8 commit 8a8ad7a

File tree

4 files changed

+71
-37
lines changed

4 files changed

+71
-37
lines changed

basex-core/src/main/java/org/basex/query/value/item/ANum.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.basex.query.value.item;
22

3+
import java.math.*;
4+
35
import org.basex.query.*;
46
import org.basex.query.CompileContext.*;
57
import org.basex.query.expr.*;
@@ -114,6 +116,43 @@ public final boolean comparable(final Item item) {
114116
return item instanceof ANum;
115117
}
116118

119+
/**
120+
* Compares a number with the numeric value of an item.
121+
* @param item value to be compared
122+
* @param transitive transitive comparison
123+
* @param ii input info
124+
* @return difference difference
125+
* @throws QueryException query exception
126+
*/
127+
final int compare(final Item item, final boolean transitive, final InputInfo ii)
128+
throws QueryException {
129+
// if possible, compare numbers as long values
130+
final Item num2;
131+
if(item.type.isUntyped()) {
132+
final byte[] string = item.string(ii);
133+
final long l = Token.toLong(string);
134+
if(l != Long.MIN_VALUE) {
135+
num2 = Itr.get(l);
136+
} else {
137+
final BigDecimal bd = Dec.parse(string, ii, false);
138+
num2 = bd != null ? Dec.get(bd) : Dbl.get(Dbl.parse(string, ii));
139+
}
140+
} else {
141+
num2 = item;
142+
}
143+
144+
if(num2 instanceof Itr itr2) {
145+
if(this instanceof Itr) return Long.compare(itr(), itr2.itr());
146+
} else if(num2 instanceof Dbl || num2 instanceof Flt) {
147+
final double d = num2.dbl(ii);
148+
if(!Double.isFinite(d)) {
149+
return d == Double.NEGATIVE_INFINITY ? 1 : d == Double.POSITIVE_INFINITY ? -1 :
150+
transitive ? 1 : NAN_DUMMY;
151+
}
152+
}
153+
return dec(ii).compareTo(num2.dec(ii));
154+
}
155+
117156
@Override
118157
public boolean test(final QueryContext qc, final InputInfo ii, final long pos)
119158
throws QueryException {

basex-core/src/main/java/org/basex/query/value/item/Dec.java

Lines changed: 29 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -163,36 +163,8 @@ static BigDecimal round(final BigDecimal value, final int prec, final RoundMode
163163
@Override
164164
public int compare(final Item item, final Collation coll, final boolean transitive,
165165
final InputInfo ii) throws QueryException {
166-
return compare(this, item, transitive, ii);
167-
}
168-
169-
/**
170-
* Compares the numeric values of two items.
171-
* @param item1 first value
172-
* @param item2 second value
173-
* @param transitive transitive comparison
174-
* @param ii input info
175-
* @return difference difference
176-
* @throws QueryException query exception
177-
*/
178-
static int compare(final Item item1, final Item item2, final boolean transitive,
179-
final InputInfo ii) throws QueryException {
180-
final Item it2;
181-
if(item2.type.isUntyped()) {
182-
final byte[] string = item2.string(ii);
183-
final BigDecimal bd = Dec.parse(string, ii, false);
184-
it2 = bd != null ? Dec.get(bd) : Dbl.get(Dbl.parse(string, ii));
185-
} else {
186-
it2 = item2;
187-
}
188-
if(it2 instanceof Dbl || it2 instanceof Flt) {
189-
final double d = it2.dbl(ii);
190-
if(!Double.isFinite(d)) {
191-
return d == Double.NEGATIVE_INFINITY ? 1 : d == Double.POSITIVE_INFINITY ? -1 :
192-
transitive ? 1 : NAN_DUMMY;
193-
}
194-
}
195-
return item1.dec(ii).compareTo(it2.dec(ii));
166+
return item instanceof final Dec dec ? value.compareTo(dec.value) :
167+
compare(item, transitive, ii);
196168
}
197169

198170
@Override
@@ -221,17 +193,39 @@ public boolean equals(final Object obj) {
221193
* @param value value to be converted
222194
* @param info input info (can be {@code null})
223195
* @param error raise error for an invalid input
224-
* @return decimal or {@code null}
196+
* @return decimal, or {@code null} value is invalid and no error is raised
225197
* @throws QueryException query exception
226198
*/
227199
public static BigDecimal parse(final byte[] value, final InputInfo info,
228200
final boolean error) throws QueryException {
229-
try {
230-
if(!contains(value, 'e') && !contains(value, 'E'))
201+
202+
// check if conversion can be successful (reject exponential notation)
203+
boolean valid = value.length != 0, dot = false;
204+
if(valid) {
205+
for(final byte v : value) {
206+
if(v == '.') {
207+
dot = true;
208+
} else if(!(digit(v) || ws(v) || v == '+' || v == '-')) {
209+
valid = false;
210+
break;
211+
}
212+
}
213+
}
214+
215+
if(valid) {
216+
// shortcut for non-fractional values
217+
if(!dot) {
218+
final long l = toLong(value);
219+
if(l != Long.MIN_VALUE) return BigDecimal.valueOf(l);
220+
}
221+
// decimal conversion
222+
try {
231223
return new BigDecimal(Token.string(value).trim());
232-
} catch(final NumberFormatException ex) {
233-
Util.debug(ex);
224+
} catch(final NumberFormatException ex) {
225+
Util.debug(ex);
226+
}
234227
}
228+
235229
if(error) throw AtomType.DECIMAL.castError(value, info);
236230
return null;
237231
}

basex-core/src/main/java/org/basex/query/value/item/Itr.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ public int toInt() {
151151
public int compare(final Item item, final Collation coll, final boolean transitive,
152152
final InputInfo ii) throws QueryException {
153153
return item instanceof final Itr itr ? Long.compare(value, itr.value) :
154-
Dec.compare(this, item, transitive, ii);
154+
compare(item, transitive, ii);
155155
}
156156

157157
@Override

basex-core/src/main/java/org/basex/query/value/item/Uln.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ public ANum round(final int prec, final RoundMode mode) {
8888
@Override
8989
public int compare(final Item item, final Collation coll, final boolean transitive,
9090
final InputInfo ii) throws QueryException {
91-
return Dec.get(dec(ii)).compare(item, coll, transitive, ii);
91+
return item instanceof final Uln uln ? value.compareTo(uln.value) :
92+
compare(item, transitive, ii);
9293
}
9394

9495
@Override

0 commit comments

Comments
 (0)