Skip to content

Commit 9ee9e8f

Browse files
authored
Moving Numeric Comparators to new framework. (#13192)
- Simplified the `GenericComparator` so a lot less code for specific type versions (building on the generic `StorageType` work). - Fix bugs with equals and not-equals when the right-hand value and column is not of same type (both Generic and Bool). - Extracted a `BinaryOperationNumeric` base class from `BinaryCoalescingOperationNumeric`. *A fair amount of boilerplate is still needed for the comparators.* - Added `NumericComparators` covering doing remaining typed comparisons. - Simplified calling comparators from the `In_Memory_Implementation`. ToDos: - Review test cases for mixed matched types in comparators (did not fail any tests before).
1 parent 0e347f5 commit 9ee9e8f

File tree

14 files changed

+934
-435
lines changed

14 files changed

+934
-435
lines changed

distribution/lib/Standard/Table/0.0.0-dev/src/Internal/In_Memory_Column_Implementation.enso

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,7 @@ type In_Memory_Column_Implementation
8282
if (a.is_a Float) || (b.is_a Float) then
8383
problem_builder.reportFloatingPointEquality -1
8484
a == b
85-
_call_comparator this_column other new_name (Comparators.eq (this_column:In_Memory_Column).java_column) <|
86-
run_vectorized_binary_op_with_fallback_problem_handling this_column Java_Storage.Maps.EQ other fallback_fn=fallback new_name=new_name expected_result_type=Value_Type.Boolean skip_nulls=True
85+
_call_comparator this_column other new_name (Comparators.eq (this_column:In_Memory_Column).java_column (_java_other other)) fallback
8786

8887
equals_ignore_case this_column (other : Column | Any) locale:Locale=Locale.default -> Column =
8988
## TODO currently this always runs the fallback which is slow due to the
@@ -100,28 +99,39 @@ type In_Memory_Column_Implementation
10099

101100
not_equals this_column (other : Column | Any) -> Column =
102101
new_name = naming_helper.binary_operation_name "!=" this_column other
103-
_call_comparator this_column other new_name (Comparators.notEq (this_column:In_Memory_Column).java_column) <|
104-
(this_column == other).not . rename new_name
102+
fallback problem_builder a b =
103+
if (a.is_a Float) || (b.is_a Float) then
104+
problem_builder.reportFloatingPointEquality -1
105+
a != b
106+
_call_comparator this_column other new_name (Comparators.notEq (this_column:In_Memory_Column).java_column (_java_other other)) fallback
105107

106108
greater_than_eq this_column (other : Column | Any) -> Column = Value_Type.expect_comparable this_column other <| Incomparable_Values.handle_errors <|
107109
new_name = naming_helper.binary_operation_name ">=" this_column other
108-
_call_comparator this_column other new_name (Comparators.greaterThanEq (this_column:In_Memory_Column).java_column) <|
109-
run_vectorized_binary_op this_column Java_Storage.Maps.GTE new_name=new_name fallback_fn=(>=) other expected_result_type=Value_Type.Boolean
110+
fallback problem_builder a b =
111+
_ = problem_builder
112+
a >= b
113+
_call_comparator this_column other new_name (Comparators.greaterThanEq (this_column:In_Memory_Column).java_column (_java_other other)) fallback
110114

111115
less_than_eq this_column (other : Column | Any) -> Column = Value_Type.expect_comparable this_column other <| Incomparable_Values.handle_errors <|
112116
new_name = naming_helper.binary_operation_name "<=" this_column other
113-
_call_comparator this_column other new_name (Comparators.lessThanEq (this_column:In_Memory_Column).java_column) <|
114-
run_vectorized_binary_op this_column Java_Storage.Maps.LTE new_name=new_name fallback_fn=(<=) other expected_result_type=Value_Type.Boolean
117+
fallback problem_builder a b =
118+
_ = problem_builder
119+
a <= b
120+
_call_comparator this_column other new_name (Comparators.lessThanEq (this_column:In_Memory_Column).java_column (_java_other other)) fallback
115121

116122
greater_than this_column (other : Column | Any) -> Column = Value_Type.expect_comparable this_column other <| Incomparable_Values.handle_errors <|
117123
new_name = naming_helper.binary_operation_name ">" this_column other
118-
_call_comparator this_column other new_name (Comparators.greaterThan (this_column:In_Memory_Column).java_column) <|
119-
run_vectorized_binary_op this_column Java_Storage.Maps.GT new_name=new_name fallback_fn=(>) other expected_result_type=Value_Type.Boolean
124+
fallback problem_builder a b =
125+
_ = problem_builder
126+
a > b
127+
_call_comparator this_column other new_name (Comparators.greaterThan (this_column:In_Memory_Column).java_column (_java_other other)) fallback
120128

121129
less_than this_column (other : Column | Any) -> Column = Value_Type.expect_comparable this_column other <| Incomparable_Values.handle_errors <|
122130
new_name = naming_helper.binary_operation_name "<" this_column other
123-
_call_comparator this_column other new_name (Comparators.lessThan (this_column:In_Memory_Column).java_column) <|
124-
run_vectorized_binary_op this_column Java_Storage.Maps.LT new_name=new_name fallback_fn=(<) other expected_result_type=Value_Type.Boolean
131+
fallback problem_builder a b =
132+
_ = problem_builder
133+
a < b
134+
_call_comparator this_column other new_name (Comparators.lessThan (this_column:In_Memory_Column).java_column (_java_other other)) fallback
125135

126136
between this_column (lower : Column | Any) (upper : Column | Any) -> Column = Value_Type.expect_comparable this_column lower <| Value_Type.expect_comparable this_column upper <|
127137
new_name = naming_helper.concat <|
@@ -947,15 +957,21 @@ apply_unary_map column:Column new_name:Text function expected_result_type:Value_
947957
map_column = UnaryOperation.mapFunction (column:In_Memory_Column).java_column function nothing_unchanged storage_type new_name java_problem_aggregator
948958
In_Memory_Column.from_java_column map_column
949959

950-
## PRIVATE
951-
Temporary function to determine if to use the Comparators statics or embedded operations.
952-
private _call_comparator left:In_Memory_Column other new_name ~comparator ~enso_action =
953-
if (Comparators.isSupported left.java_column) == False then enso_action else
954-
_call_binary_operator left other new_name comparator
960+
private _java_other other =
961+
if other.is_a Column then (other:In_Memory_Column).java_column else
962+
enso_to_java other
963+
964+
private _call_comparator left other new_name ~comparator fallback =
965+
case (Comparators.isSupported (left:In_Memory_Column).java_column) of
966+
True -> _call_binary_operator left other new_name comparator
967+
False ->
968+
Java_Problems.with_map_operation_problem_aggregator new_name Problem_Behavior.Report_Warning java_problem_aggregator->
969+
fallback_fn = fallback java_problem_aggregator
970+
run_binary_op left fallback_fn other new_name skip_nulls=True expected_result_type=Value_Type.Boolean
955971

956972
private _call_binary_operator left:In_Memory_Column other new_name ~operation =
957973
Java_Problems.with_map_operation_problem_aggregator new_name Problem_Behavior.Report_Warning java_problem_aggregator->
958-
java_column = operation.apply left.java_column (if other.is_a Column then (other:In_Memory_Column).java_column else other) new_name java_problem_aggregator
974+
java_column = operation.apply left.java_column (_java_other other) new_name java_problem_aggregator
959975
In_Memory_Column.from_java_column java_column
960976

961977
## PRIVATE

std-bits/table/src/main/java/org/enso/table/data/column/operation/BinaryCoalescingOperationNumeric.java

Lines changed: 50 additions & 178 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,11 @@
66
import org.enso.table.data.column.storage.ColumnDoubleStorage;
77
import org.enso.table.data.column.storage.ColumnLongStorage;
88
import org.enso.table.data.column.storage.ColumnStorage;
9-
import org.enso.table.data.column.storage.ColumnStorageFacade;
10-
import org.enso.table.data.column.storage.PreciseTypeOptions;
11-
import org.enso.table.data.column.storage.numeric.DoubleStorageFacade;
129
import org.enso.table.data.column.storage.type.BigDecimalType;
1310
import org.enso.table.data.column.storage.type.BigIntegerType;
1411
import org.enso.table.data.column.storage.type.FloatType;
1512
import org.enso.table.data.column.storage.type.IntegerType;
16-
import org.enso.table.data.column.storage.type.NullType;
1713
import org.enso.table.data.column.storage.type.StorageType;
18-
import org.enso.table.data.table.Column;
1914

2015
/**
2116
* A binary coalescing operation for numeric types. This class is used to perform operations on two
@@ -26,7 +21,7 @@
2621
*
2722
* @param <T> the type of the elements in the column
2823
*/
29-
public abstract class BinaryCoalescingOperationNumeric<T> implements BinaryOperation<T> {
24+
public abstract class BinaryCoalescingOperationNumeric<T> extends BinaryOperationNumeric<T, T> {
3025
/**
3126
* An abstract class representing a numeric operation. This class defines the methods that must be
3227
* implemented by any numeric operation.
@@ -103,112 +98,24 @@ public static BinaryOperation<?> create(
10398
}
10499
}
105100

106-
private static StorageType<?> storageTypeForObject(Object right) {
107-
if (right == null) {
108-
return NullType.INSTANCE;
109-
}
110-
111-
if (right instanceof Column rightColumn) {
112-
return rightColumn.getStorage().getType();
113-
}
114-
115-
return StorageType.forBoxedItem(right, PreciseTypeOptions.DEFAULT);
116-
}
117-
118-
protected final StorageType<T> validType;
119101
protected final NumericOperation operation;
120-
protected final StorageType<?>[] validInputs;
121102

122103
protected BinaryCoalescingOperationNumeric(
123-
StorageType<T> validType, NumericOperation operation, StorageType<?>... validInputs) {
124-
this.validType = validType;
104+
NumericColumnAdapter<T> adapter, StorageType<T> returnType, NumericOperation operation) {
105+
super(adapter, false, returnType);
125106
this.operation = operation;
126-
this.validInputs = validInputs;
127107
}
128108

129109
@Override
130-
public boolean canApplyMap(ColumnStorage<?> left, Object rightValue) {
131-
var leftType = left.getType();
132-
if (validType.isOfType(leftType)) {
133-
return true;
134-
}
135-
136-
for (var validInput : validInputs) {
137-
if (validInput.isOfType(leftType)) {
138-
return true;
139-
}
140-
}
141-
142-
return false;
143-
}
144-
145-
@Override
146-
public boolean canApplyZip(ColumnStorage<?> left, ColumnStorage<?> right) {
147-
return canApplyMap(left, null) && canApplyMap(right, null);
110+
protected ColumnStorage<T> applyNullMap(
111+
ColumnStorage<?> left, MapOperationProblemAggregator problemAggregator) {
112+
return adapter.asTypedStorage(left);
148113
}
149114

150-
@Override
151-
public ColumnStorage<T> applyMap(
152-
ColumnStorage<?> left, Object rightValue, MapOperationProblemAggregator problemAggregator) {
153-
if (rightValue == null) {
154-
return asTypedStorage(left);
155-
}
156-
157-
T rightValueTyped = validType.valueAsType(rightValue);
158-
if (rightValueTyped == null) {
159-
throw new IllegalArgumentException(
160-
"Unsupported right value type " + rightValue.getClass() + ".");
161-
}
162-
163-
return innerApplyMap(asTypedStorage(left), rightValueTyped, problemAggregator);
164-
}
165-
166-
@Override
167-
public ColumnStorage<T> applyZip(
168-
ColumnStorage<?> left,
169-
ColumnStorage<?> right,
170-
MapOperationProblemAggregator problemAggregator) {
171-
if (NullType.INSTANCE.isOfType(right.getType())) {
172-
return validType.asTypedStorage(left);
173-
}
174-
175-
return innerApplyZip(asTypedStorage(left), asTypedStorage(right), problemAggregator);
176-
}
177-
178-
protected abstract ColumnStorage<T> asTypedStorage(ColumnStorage<?> storage);
179-
180-
protected abstract ColumnStorage<T> innerApplyMap(
181-
ColumnStorage<T> left, T right, MapOperationProblemAggregator problemAggregator);
182-
183-
protected abstract ColumnStorage<T> innerApplyZip(
184-
ColumnStorage<T> left,
185-
ColumnStorage<T> right,
186-
MapOperationProblemAggregator problemAggregator);
187-
188115
private static class BinaryCoalescingOperationDouble
189116
extends BinaryCoalescingOperationNumeric<Double> {
190117
public BinaryCoalescingOperationDouble(NumericOperation operation) {
191-
super(
192-
FloatType.FLOAT_64,
193-
operation,
194-
BigDecimalType.INSTANCE,
195-
BigIntegerType.INSTANCE,
196-
IntegerType.INT_64);
197-
}
198-
199-
@Override
200-
protected ColumnDoubleStorage asTypedStorage(ColumnStorage<?> storage) {
201-
return switch (storage.getType()) {
202-
case FloatType floatType -> floatType.asTypedStorage(storage);
203-
case BigDecimalType bigDecimalType -> DoubleStorageFacade.forBigDecimal(
204-
bigDecimalType.asTypedStorage(storage));
205-
case BigIntegerType bigIntegerType -> DoubleStorageFacade.forBigInteger(
206-
bigIntegerType.asTypedStorage(storage));
207-
case IntegerType integerType -> DoubleStorageFacade.forLong(
208-
integerType.asTypedStorage(storage));
209-
default -> throw new IllegalArgumentException(
210-
"Unsupported storage type: " + storage.getType());
211-
};
118+
super(DoubleColumnAdapter.INSTANCE, FloatType.FLOAT_64, operation);
212119
}
213120

214121
@Override
@@ -245,107 +152,60 @@ protected ColumnStorage<Double> innerApplyZip(
245152
}
246153
});
247154
}
248-
}
249-
250-
private abstract static class BinaryCoalescingOperationBigNumber<T>
251-
extends BinaryCoalescingOperationNumeric<T> {
252-
protected BinaryCoalescingOperationBigNumber(
253-
StorageType<T> validType, NumericOperation operation, StorageType<?>... validInputs) {
254-
super(validType, operation, validInputs);
255-
}
256-
257-
@Override
258-
protected ColumnStorage<T> innerApplyMap(
259-
ColumnStorage<T> left, T right, MapOperationProblemAggregator problemAggregator) {
260-
return StorageIterators.mapOverStorage(
261-
left,
262-
false,
263-
validType.makeBuilder(left.getSize(), problemAggregator),
264-
(index, value) -> value == null ? right : doSingle(value, right, index));
265-
}
266155

267156
@Override
268-
protected ColumnStorage<T> innerApplyZip(
269-
ColumnStorage<T> left,
270-
ColumnStorage<T> right,
271-
MapOperationProblemAggregator problemAggregator) {
272-
return StorageIterators.zipOverStorages(
273-
left,
274-
right,
275-
size -> validType.makeBuilder(size, problemAggregator),
276-
false,
277-
(index, x, y) -> {
278-
if (x == null) {
279-
return y;
280-
} else {
281-
return y == null ? x : doSingle(x, y, index);
282-
}
283-
});
157+
protected Double doSingle(
158+
Double left, Double right, long index, MapOperationProblemAggregator problemAggregator) {
159+
if (left == null) {
160+
return right;
161+
} else if (right == null) {
162+
return left;
163+
} else {
164+
return operation.doDouble(left, right, index);
165+
}
284166
}
285-
286-
protected abstract T doSingle(T left, T right, long index);
287167
}
288168

289169
private static class BinaryCoalescingOperationBigDecimal
290-
extends BinaryCoalescingOperationBigNumber<BigDecimal> {
170+
extends BinaryCoalescingOperationNumeric<BigDecimal> {
291171
public BinaryCoalescingOperationBigDecimal(NumericOperation operation) {
292-
super(BigDecimalType.INSTANCE, operation, BigIntegerType.INSTANCE, IntegerType.INT_64);
293-
}
294-
295-
@Override
296-
protected ColumnStorage<BigDecimal> asTypedStorage(ColumnStorage<?> storage) {
297-
return switch (storage.getType()) {
298-
case BigDecimalType bigDecimalType -> bigDecimalType.asTypedStorage(storage);
299-
case BigIntegerType bigIntegerType -> new ColumnStorageFacade<>(
300-
bigIntegerType.asTypedStorage(storage), BigDecimal::new);
301-
case IntegerType integerType -> new ColumnStorageFacade<>(
302-
integerType.asTypedStorage(storage), BigDecimal::valueOf);
303-
default -> throw new IllegalArgumentException(
304-
"Unsupported storage type: " + storage.getType());
305-
};
172+
super(BigDecimalColumnAdapter.INSTANCE, BigDecimalType.INSTANCE, operation);
306173
}
307174

308175
@Override
309-
protected BigDecimal doSingle(BigDecimal left, BigDecimal right, long index) {
310-
return operation.doBigDecimal(left, right, index);
176+
protected BigDecimal doSingle(
177+
BigDecimal left,
178+
BigDecimal right,
179+
long index,
180+
MapOperationProblemAggregator problemAggregator) {
181+
return left == null
182+
? right
183+
: (right == null ? left : operation.doBigDecimal(left, right, index));
311184
}
312185
}
313186

314187
private static class BinaryCoalescingOperationBigInteger
315-
extends BinaryCoalescingOperationBigNumber<BigInteger> {
188+
extends BinaryCoalescingOperationNumeric<BigInteger> {
316189
public BinaryCoalescingOperationBigInteger(NumericOperation operation) {
317-
super(BigIntegerType.INSTANCE, operation, IntegerType.INT_64);
318-
}
319-
320-
@Override
321-
protected ColumnStorage<BigInteger> asTypedStorage(ColumnStorage<?> storage) {
322-
return switch (storage.getType()) {
323-
case BigIntegerType bigIntegerType -> bigIntegerType.asTypedStorage(storage);
324-
case IntegerType integerType -> new ColumnStorageFacade<>(
325-
integerType.asTypedStorage(storage), BigInteger::valueOf);
326-
default -> throw new IllegalArgumentException(
327-
"Unsupported storage type: " + storage.getType());
328-
};
190+
super(BigIntegerColumnAdapter.INSTANCE, BigIntegerType.INSTANCE, operation);
329191
}
330192

331193
@Override
332-
protected BigInteger doSingle(BigInteger left, BigInteger right, long index) {
333-
return operation.doBigInteger(left, right, index);
194+
protected BigInteger doSingle(
195+
BigInteger left,
196+
BigInteger right,
197+
long index,
198+
MapOperationProblemAggregator problemAggregator) {
199+
return left == null
200+
? right
201+
: (right == null ? left : operation.doBigInteger(left, right, index));
334202
}
335203
}
336204

337205
private static class BinaryCoalescingOperationLong
338206
extends BinaryCoalescingOperationNumeric<Long> {
339207
public BinaryCoalescingOperationLong(NumericOperation operation) {
340-
super(IntegerType.INT_64, operation);
341-
}
342-
343-
@Override
344-
protected ColumnLongStorage asTypedStorage(ColumnStorage<?> storage) {
345-
if (storage.getType() instanceof IntegerType integerType) {
346-
return integerType.asTypedStorage(storage);
347-
}
348-
throw new IllegalArgumentException("Unsupported storage type: " + storage.getType());
208+
super(LongColumnAdapter.INSTANCE, IntegerType.INT_64, operation);
349209
}
350210

351211
@Override
@@ -368,7 +228,7 @@ protected ColumnStorage<Long> innerApplyZip(
368228
return StorageIterators.zipOverLongStorages(
369229
(ColumnLongStorage) left,
370230
(ColumnLongStorage) right,
371-
s -> validType.makeBuilder(s, problemAggregator),
231+
s -> IntegerType.INT_64.makeBuilder(s, problemAggregator),
372232
true,
373233
(index, value1, isNothing1, value2, isNothing2) -> {
374234
if (isNothing1 && isNothing2) {
@@ -382,5 +242,17 @@ protected ColumnStorage<Long> innerApplyZip(
382242
}
383243
});
384244
}
245+
246+
@Override
247+
protected Long doSingle(
248+
Long left, Long right, long index, MapOperationProblemAggregator problemAggregator) {
249+
if (left == null) {
250+
return right;
251+
} else if (right == null) {
252+
return left;
253+
} else {
254+
return operation.doLong(left, right, index);
255+
}
256+
}
385257
}
386258
}

0 commit comments

Comments
 (0)