2
2
3
3
import java .util .BitSet ;
4
4
import java .util .List ;
5
+ import org .enso .table .data .column .builder .BoolBuilder ;
6
+ import org .enso .table .data .column .operation .map .BinaryMapOperation ;
5
7
import org .enso .table .data .column .operation .map .MapOperationProblemAggregator ;
8
+ import org .enso .table .data .column .operation .map .MapOperationStorage ;
6
9
import org .enso .table .data .column .storage .type .NullType ;
7
10
import org .enso .table .data .column .storage .type .StorageType ;
8
11
import org .enso .table .data .mask .OrderMask ;
9
12
import org .enso .table .data .mask .SliceRange ;
13
+ import org .enso .table .error .UnexpectedColumnTypeException ;
14
+ import org .enso .table .error .UnexpectedTypeException ;
15
+ import org .graalvm .polyglot .Value ;
10
16
11
17
/** A specialized storage that can be used by columns that contain only null values. */
12
18
public class NullStorage extends Storage <Void > {
13
19
private final int size ;
20
+ private final MapOperationStorage <Void , NullStorage > ops = buildOps ();
14
21
15
22
public NullStorage (int size ) {
16
23
this .size = size ;
@@ -36,26 +43,66 @@ public Void getItemBoxed(int idx) {
36
43
return null ;
37
44
}
38
45
46
+ private static MapOperationStorage <Void , NullStorage > buildOps () {
47
+ MapOperationStorage <Void , NullStorage > ops = new MapOperationStorage <>();
48
+ ops .add (new NullOp (Maps .EQ ));
49
+ ops .add (new NullOp (Maps .LT ));
50
+ ops .add (new NullOp (Maps .LTE ));
51
+ ops .add (new NullOp (Maps .GT ));
52
+ ops .add (new NullOp (Maps .GTE ));
53
+
54
+ ops .add (new NullOp (Maps .MUL ));
55
+ ops .add (new NullOp (Maps .ADD ));
56
+ ops .add (new NullOp (Maps .SUB ));
57
+ ops .add (new NullOp (Maps .DIV ));
58
+ ops .add (new NullOp (Maps .MOD ));
59
+ ops .add (new NullOp (Maps .POWER ));
60
+
61
+ ops .add (new NullAndOp ());
62
+ ops .add (new NullOrOp ());
63
+
64
+ ops .add (new NullOp (Maps .STARTS_WITH ));
65
+ ops .add (new NullOp (Maps .ENDS_WITH ));
66
+ ops .add (new NullOp (Maps .CONTAINS ));
67
+ ops .add (new NullOp (Maps .LIKE ));
68
+ ops .add (new NullOp (Maps .TEXT_LEFT ));
69
+ ops .add (new NullOp (Maps .TEXT_RIGHT ));
70
+
71
+ ops .add (new CoalescingNullOp (Maps .MIN ));
72
+ ops .add (new CoalescingNullOp (Maps .MAX ));
73
+
74
+ return ops ;
75
+ }
76
+
39
77
@ Override
40
78
public boolean isBinaryOpVectorized (String name ) {
41
- return false ;
79
+ return ops . isSupportedBinary ( name ) ;
42
80
}
43
81
44
82
@ Override
45
83
public Storage <?> runVectorizedBinaryMap (
46
84
String name , Object argument , MapOperationProblemAggregator problemAggregator ) {
47
- throw new IllegalArgumentException ( "Operation " + name + " is not vectorized for NullStorage" );
85
+ return ops . runBinaryMap ( name , this , argument , problemAggregator );
48
86
}
49
87
50
88
@ Override
51
89
public Storage <?> runVectorizedZip (
52
90
String name , Storage <?> argument , MapOperationProblemAggregator problemAggregator ) {
53
- throw new IllegalArgumentException ( "Operation " + name + " is not vectorized for NullStorage" );
91
+ return ops . runZip ( name , this , argument , problemAggregator );
54
92
}
55
93
56
94
@ Override
57
- public Storage <?> fillMissingFromPrevious (BoolStorage missingIndicator ) {
58
- return this ;
95
+ public boolean isTernaryOpVectorized (String name ) {
96
+ return ops .isSupportedTernary (name );
97
+ }
98
+
99
+ @ Override
100
+ public Storage <?> runVectorizedTernaryMap (
101
+ String name ,
102
+ Object argument0 ,
103
+ Object argument1 ,
104
+ MapOperationProblemAggregator problemAggregator ) {
105
+ return ops .runTernaryMap (name , this , argument0 , argument1 , problemAggregator );
59
106
}
60
107
61
108
@ Override
@@ -82,4 +129,123 @@ public Storage<?> appendNulls(int count) {
82
129
public Storage <Void > slice (List <SliceRange > ranges ) {
83
130
return new NullStorage (SliceRange .totalLength (ranges ));
84
131
}
132
+
133
+ @ Override
134
+ public Storage <?> fillMissingFromPrevious (BoolStorage missingIndicator ) {
135
+ return this ;
136
+ }
137
+
138
+ /** A binary operation that always returns null. */
139
+ private static class NullOp extends BinaryMapOperation <Void , NullStorage > {
140
+ public NullOp (String name ) {
141
+ super (name );
142
+ }
143
+
144
+ @ Override
145
+ public Storage <?> runBinaryMap (
146
+ NullStorage storage , Object arg , MapOperationProblemAggregator problemAggregator ) {
147
+ // We return the same storage as-is, because all lhs arguments are guaranteed to be null.
148
+ return storage ;
149
+ }
150
+
151
+ @ Override
152
+ public Storage <?> runZip (
153
+ NullStorage storage , Storage <?> arg , MapOperationProblemAggregator problemAggregator ) {
154
+ // We return the same storage as-is, because all lhs arguments are guaranteed to be null.
155
+ return storage ;
156
+ }
157
+ }
158
+
159
+ /**
160
+ * A binary operation that always returns the other argument.
161
+ *
162
+ * <p>Useful for implementing operations that should return the other argument when the left-hand
163
+ * side is null, e.g. min.
164
+ */
165
+ private static class CoalescingNullOp extends BinaryMapOperation <Void , NullStorage > {
166
+ public CoalescingNullOp (String name ) {
167
+ super (name );
168
+ }
169
+
170
+ @ Override
171
+ public Storage <?> runBinaryMap (
172
+ NullStorage storage , Object arg , MapOperationProblemAggregator problemAggregator ) {
173
+ return Storage .fromRepeatedItem (Value .asValue (arg ), storage .size (), problemAggregator );
174
+ }
175
+
176
+ @ Override
177
+ public Storage <?> runZip (
178
+ NullStorage storage , Storage <?> arg , MapOperationProblemAggregator problemAggregator ) {
179
+ return arg ;
180
+ }
181
+ }
182
+
183
+ private abstract static class BoolAndNullOp extends BinaryMapOperation <Void , NullStorage > {
184
+ public BoolAndNullOp (String name ) {
185
+ super (name );
186
+ }
187
+
188
+ protected abstract Boolean doBool (boolean a );
189
+
190
+ @ Override
191
+ public Storage <?> runBinaryMap (
192
+ NullStorage storage , Object arg , MapOperationProblemAggregator problemAggregator ) {
193
+ if (arg == null ) {
194
+ return new NullStorage (storage .size ());
195
+ } else if (arg instanceof Boolean b ) {
196
+ return Storage .fromRepeatedItem (
197
+ Value .asValue (doBool (b )), storage .size (), problemAggregator );
198
+ } else {
199
+ throw new UnexpectedTypeException ("Boolean" , arg .toString ());
200
+ }
201
+ }
202
+
203
+ @ Override
204
+ public Storage <?> runZip (
205
+ NullStorage storage , Storage <?> arg , MapOperationProblemAggregator problemAggregator ) {
206
+ if (arg instanceof BoolStorage boolStorage ) {
207
+ BoolBuilder builder = new BoolBuilder (storage .size ());
208
+ for (int i = 0 ; i < storage .size (); i ++) {
209
+ if (boolStorage .isNothing (i )) {
210
+ builder .appendNulls (1 );
211
+ } else {
212
+ builder .append (doBool (boolStorage .getItem (i )));
213
+ }
214
+ }
215
+ return builder .seal ();
216
+ } else {
217
+ throw new UnexpectedColumnTypeException ("Boolean" );
218
+ }
219
+ }
220
+ }
221
+
222
+ private static class NullAndOp extends BoolAndNullOp {
223
+ public NullAndOp () {
224
+ super (Maps .AND );
225
+ }
226
+
227
+ @ Override
228
+ protected Boolean doBool (boolean a ) {
229
+ if (a ) {
230
+ return null ;
231
+ } else {
232
+ return false ;
233
+ }
234
+ }
235
+ }
236
+
237
+ private static class NullOrOp extends BoolAndNullOp {
238
+ public NullOrOp () {
239
+ super (Maps .OR );
240
+ }
241
+
242
+ @ Override
243
+ protected Boolean doBool (boolean a ) {
244
+ if (a ) {
245
+ return true ;
246
+ } else {
247
+ return null ;
248
+ }
249
+ }
250
+ }
85
251
}
0 commit comments