@@ -119,7 +119,7 @@ private Delegate CreateGetter(int index)
119
119
120
120
var column = DataView . _schema . SchemaDefn . Columns [ index ] ;
121
121
var outputType = column . IsComputed ? column . ReturnType : column . FieldInfo . FieldType ;
122
-
122
+ var genericType = outputType ;
123
123
Func < int , Delegate > del ;
124
124
125
125
if ( outputType . IsArray )
@@ -129,11 +129,66 @@ private Delegate CreateGetter(int index)
129
129
if ( outputType . GetElementType ( ) == typeof ( string ) )
130
130
{
131
131
Ch . Assert ( colType . ItemType . IsText ) ;
132
- return CreateStringArrayToVBufferGetter ( index ) ;
132
+ return CreateConvertingArrayGetterDelegate < String , DvText > ( index , x => x == null ? DvText . NA : new DvText ( x ) ) ;
133
+ }
134
+ else if ( outputType . GetElementType ( ) == typeof ( int ) )
135
+ {
136
+ Ch . Assert ( colType . ItemType == NumberType . I4 ) ;
137
+ return CreateConvertingArrayGetterDelegate < int , DvInt4 > ( index , x => x ) ;
138
+ }
139
+ else if ( outputType . GetElementType ( ) == typeof ( int ? ) )
140
+ {
141
+ Ch . Assert ( colType . ItemType == NumberType . I4 ) ;
142
+ return CreateConvertingArrayGetterDelegate < int ? , DvInt4 > ( index , x => x ?? DvInt4 . NA ) ;
143
+ }
144
+ else if ( outputType . GetElementType ( ) == typeof ( long ) )
145
+ {
146
+ Ch . Assert ( colType . ItemType == NumberType . I8 ) ;
147
+ return CreateConvertingArrayGetterDelegate < long , DvInt8 > ( index , x => x ) ;
148
+ }
149
+ else if ( outputType . GetElementType ( ) == typeof ( long ? ) )
150
+ {
151
+ Ch . Assert ( colType . ItemType == NumberType . I8 ) ;
152
+ return CreateConvertingArrayGetterDelegate < long ? , DvInt8 > ( index , x => x ?? DvInt8 . NA ) ;
153
+ }
154
+ else if ( outputType . GetElementType ( ) == typeof ( short ) )
155
+ {
156
+ Ch . Assert ( colType . ItemType == NumberType . I2 ) ;
157
+ return CreateConvertingArrayGetterDelegate < short , DvInt2 > ( index , x => x ) ;
158
+ }
159
+ else if ( outputType . GetElementType ( ) == typeof ( short ? ) )
160
+ {
161
+ Ch . Assert ( colType . ItemType == NumberType . I2 ) ;
162
+ return CreateConvertingArrayGetterDelegate < short ? , DvInt2 > ( index , x => x ?? DvInt2 . NA ) ;
163
+ }
164
+ else if ( outputType . GetElementType ( ) == typeof ( sbyte ) )
165
+ {
166
+ Ch . Assert ( colType . ItemType == NumberType . I1 ) ;
167
+ return CreateConvertingArrayGetterDelegate < sbyte , DvInt1 > ( index , x => x ) ;
133
168
}
169
+ else if ( outputType . GetElementType ( ) == typeof ( sbyte ? ) )
170
+ {
171
+ Ch . Assert ( colType . ItemType == NumberType . I1 ) ;
172
+ return CreateConvertingArrayGetterDelegate < sbyte ? , DvInt1 > ( index , x => x ?? DvInt1 . NA ) ;
173
+ }
174
+ else if ( outputType . GetElementType ( ) == typeof ( bool ) )
175
+ {
176
+ Ch . Assert ( colType . ItemType . IsBool ) ;
177
+ return CreateConvertingArrayGetterDelegate < bool , DvBool > ( index , x => x ) ;
178
+ }
179
+ else if ( outputType . GetElementType ( ) == typeof ( bool ? ) )
180
+ {
181
+ Ch . Assert ( colType . ItemType . IsBool ) ;
182
+ return CreateConvertingArrayGetterDelegate < bool ? , DvBool > ( index , x => x ?? DvBool . NA ) ;
183
+ }
184
+
134
185
// T[] -> VBuffer<T>
135
- Ch . Assert ( outputType . GetElementType ( ) == colType . ItemType . RawType ) ;
136
- del = CreateArrayToVBufferGetter < int > ;
186
+ if ( outputType . GetElementType ( ) . IsGenericType && outputType . GetElementType ( ) . GetGenericTypeDefinition ( ) == typeof ( Nullable < > ) )
187
+ Ch . Assert ( Nullable . GetUnderlyingType ( outputType . GetElementType ( ) ) == colType . ItemType . RawType ) ;
188
+ else
189
+ Ch . Assert ( outputType . GetElementType ( ) == colType . ItemType . RawType ) ;
190
+ del = CreateDirectArrayGetterDelegate < int > ;
191
+ genericType = outputType . GetElementType ( ) ;
137
192
}
138
193
else if ( colType . IsVector )
139
194
{
@@ -142,99 +197,126 @@ private Delegate CreateGetter(int index)
142
197
Ch . Assert ( outputType . IsGenericType ) ;
143
198
Ch . Assert ( outputType . GetGenericTypeDefinition ( ) == typeof ( VBuffer < > ) ) ;
144
199
Ch . Assert ( outputType . GetGenericArguments ( ) [ 0 ] == colType . ItemType . RawType ) ;
145
- del = CreateVBufferToVBufferDelegate < int > ;
200
+ del = CreateDirectVBufferGetterDelegate < int > ;
146
201
}
147
202
else if ( colType . IsPrimitive )
148
203
{
149
204
if ( outputType == typeof ( string ) )
150
205
{
151
206
// String -> DvText
152
207
Ch . Assert ( colType . IsText ) ;
153
- return CreateStringToTextGetter ( index ) ;
208
+ return CreateConvertingGetterDelegate < String , DvText > ( index , x => x == null ? DvText . NA : new DvText ( x ) ) ;
154
209
}
155
210
else if ( outputType == typeof ( bool ) )
156
211
{
157
212
// Bool -> DvBool
158
213
Ch . Assert ( colType . IsBool ) ;
159
- return CreateBooleanToDvBoolGetter ( index ) ;
214
+ return CreateConvertingGetterDelegate < bool , DvBool > ( index , x => x ) ;
160
215
}
161
216
else if ( outputType == typeof ( bool ? ) )
162
217
{
163
218
// Bool? -> DvBool
164
219
Ch . Assert ( colType . IsBool ) ;
165
- return CreateNullableBooleanToDvBoolGetter ( index ) ;
220
+ return CreateConvertingGetterDelegate < bool ? , DvBool > ( index , x => x ?? DvBool . NA ) ;
221
+ }
222
+ else if ( outputType == typeof ( int ) )
223
+ {
224
+ // int -> DvInt4
225
+ Ch . Assert ( colType == NumberType . I4 ) ;
226
+ return CreateConvertingGetterDelegate < int , DvInt4 > ( index , x => x ) ;
227
+ }
228
+ else if ( outputType == typeof ( int ? ) )
229
+ {
230
+ // int? -> DvInt4
231
+ Ch . Assert ( colType == NumberType . I4 ) ;
232
+ return CreateConvertingGetterDelegate < int ? , DvInt4 > ( index , x => x ?? DvInt4 . NA ) ;
233
+ }
234
+ else if ( outputType == typeof ( short ) )
235
+ {
236
+ // short -> DvInt2
237
+ Ch . Assert ( colType == NumberType . I2 ) ;
238
+ return CreateConvertingGetterDelegate < short , DvInt2 > ( index , x => x ) ;
239
+ }
240
+ else if ( outputType == typeof ( short ? ) )
241
+ {
242
+ // short? -> DvInt2
243
+ Ch . Assert ( colType == NumberType . I2 ) ;
244
+ return CreateConvertingGetterDelegate < short ? , DvInt2 > ( index , x => x ?? DvInt2 . NA ) ;
245
+ }
246
+ else if ( outputType == typeof ( long ) )
247
+ {
248
+ // long -> DvInt8
249
+ Ch . Assert ( colType == NumberType . I8 ) ;
250
+ return CreateConvertingGetterDelegate < long , DvInt8 > ( index , x => x ) ;
251
+ }
252
+ else if ( outputType == typeof ( long ? ) )
253
+ {
254
+ // long? -> DvInt8
255
+ Ch . Assert ( colType == NumberType . I8 ) ;
256
+ return CreateConvertingGetterDelegate < long ? , DvInt8 > ( index , x => x ?? DvInt8 . NA ) ;
257
+ }
258
+ else if ( outputType == typeof ( sbyte ) )
259
+ {
260
+ // sbyte -> DvInt1
261
+ Ch . Assert ( colType == NumberType . I1 ) ;
262
+ return CreateConvertingGetterDelegate < sbyte , DvInt1 > ( index , x => x ) ;
263
+ }
264
+ else if ( outputType == typeof ( sbyte ? ) )
265
+ {
266
+ // sbyte? -> DvInt1
267
+ Ch . Assert ( colType == NumberType . I1 ) ;
268
+ return CreateConvertingGetterDelegate < sbyte ? , DvInt1 > ( index , x => x ?? DvInt1 . NA ) ;
166
269
}
167
-
168
270
// T -> T
169
- Ch . Assert ( colType . RawType == outputType ) ;
170
- del = CreateDirectGetter < int > ;
271
+ if ( outputType . IsGenericType && outputType . GetGenericTypeDefinition ( ) == typeof ( Nullable < > ) )
272
+ Ch . Assert ( colType . RawType == Nullable . GetUnderlyingType ( outputType ) ) ;
273
+ else
274
+ Ch . Assert ( colType . RawType == outputType ) ;
275
+ del = CreateDirectGetterDelegate < int > ;
171
276
}
172
277
else
173
278
{
174
279
// REVIEW: Is this even possible?
175
280
throw Ch . ExceptNotImpl ( "Type '{0}' is not yet supported." , outputType . FullName ) ;
176
281
}
177
282
MethodInfo meth =
178
- del . GetMethodInfo ( ) . GetGenericMethodDefinition ( ) . MakeGenericMethod ( colType . ItemType . RawType ) ;
283
+ del . GetMethodInfo ( ) . GetGenericMethodDefinition ( ) . MakeGenericMethod ( genericType ) ;
179
284
return ( Delegate ) meth . Invoke ( this , new object [ ] { index } ) ;
180
285
}
181
286
182
- private Delegate CreateStringArrayToVBufferGetter ( int index )
287
+ // REVIEW: The converting getter invokes a type conversion delegate on every call, so it's inherently slower
288
+ // than the 'direct' getter. We don't have good indication of this to the user, and the selection
289
+ // of affected types is pretty arbitrary (signed integers and bools, but not uints and floats).
290
+ private Delegate CreateConvertingArrayGetterDelegate < TSrc , TDst > ( int index , Func < TSrc , TDst > convert )
183
291
{
184
- var peek = DataView . _peeks [ index ] as Peek < TRow , string [ ] > ;
292
+ var peek = DataView . _peeks [ index ] as Peek < TRow , TSrc [ ] > ;
185
293
Ch . AssertValue ( peek ) ;
186
-
187
- string [ ] buf = null ;
188
-
189
- return ( ValueGetter < VBuffer < DvText > > ) ( ( ref VBuffer < DvText > dst ) =>
294
+ TSrc [ ] buf = default ;
295
+ return ( ValueGetter < VBuffer < TDst > > ) ( ( ref VBuffer < TDst > dst ) =>
190
296
{
191
297
peek ( GetCurrentRowObject ( ) , Position , ref buf ) ;
192
298
var n = Utils . Size ( buf ) ;
193
- dst = new VBuffer < DvText > ( n , Utils . Size ( dst . Values ) < n
194
- ? new DvText [ n ]
299
+ dst = new VBuffer < TDst > ( n , Utils . Size ( dst . Values ) < n
300
+ ? new TDst [ n ]
195
301
: dst . Values , dst . Indices ) ;
196
302
for ( int i = 0 ; i < n ; i ++ )
197
- dst . Values [ i ] = new DvText ( buf [ i ] ) ;
198
- } ) ;
199
- }
200
-
201
- private Delegate CreateStringToTextGetter ( int index )
202
- {
203
- var peek = DataView . _peeks [ index ] as Peek < TRow , string > ;
204
- Ch . AssertValue ( peek ) ;
205
- string buf = null ;
206
- return ( ValueGetter < DvText > ) ( ( ref DvText dst ) =>
207
- {
208
- peek ( GetCurrentRowObject ( ) , Position , ref buf ) ;
209
- dst = new DvText ( buf ) ;
210
- } ) ;
211
- }
212
-
213
- private Delegate CreateBooleanToDvBoolGetter ( int index )
214
- {
215
- var peek = DataView . _peeks [ index ] as Peek < TRow , bool > ;
216
- Ch . AssertValue ( peek ) ;
217
- bool buf = false ;
218
- return ( ValueGetter < DvBool > ) ( ( ref DvBool dst ) =>
219
- {
220
- peek ( GetCurrentRowObject ( ) , Position , ref buf ) ;
221
- dst = ( DvBool ) buf ;
303
+ dst . Values [ i ] = convert ( buf [ i ] ) ;
222
304
} ) ;
223
305
}
224
306
225
- private Delegate CreateNullableBooleanToDvBoolGetter ( int index )
307
+ private Delegate CreateConvertingGetterDelegate < TSrc , TDst > ( int index , Func < TSrc , TDst > convert )
226
308
{
227
- var peek = DataView . _peeks [ index ] as Peek < TRow , bool ? > ;
309
+ var peek = DataView . _peeks [ index ] as Peek < TRow , TSrc > ;
228
310
Ch . AssertValue ( peek ) ;
229
- bool ? buf = null ;
230
- return ( ValueGetter < DvBool > ) ( ( ref DvBool dst ) =>
311
+ TSrc buf = default ;
312
+ return ( ValueGetter < TDst > ) ( ( ref TDst dst ) =>
231
313
{
232
314
peek ( GetCurrentRowObject ( ) , Position , ref buf ) ;
233
- dst = buf . HasValue ? ( DvBool ) buf . Value : DvBool . NA ;
315
+ dst = convert ( buf ) ;
234
316
} ) ;
235
317
}
236
318
237
- private Delegate CreateArrayToVBufferGetter < TDst > ( int index )
319
+ private Delegate CreateDirectArrayGetterDelegate < TDst > ( int index )
238
320
{
239
321
var peek = DataView . _peeks [ index ] as Peek < TRow , TDst [ ] > ;
240
322
Ch . AssertValue ( peek ) ;
@@ -250,26 +332,29 @@ private Delegate CreateArrayToVBufferGetter<TDst>(int index)
250
332
} ) ;
251
333
}
252
334
253
- private Delegate CreateVBufferToVBufferDelegate < TDst > ( int index )
335
+ private Delegate CreateDirectVBufferGetterDelegate < TDst > ( int index )
254
336
{
255
337
var peek = DataView . _peeks [ index ] as Peek < TRow , VBuffer < TDst > > ;
256
338
Ch . AssertValue ( peek ) ;
257
339
VBuffer < TDst > buf = default ( VBuffer < TDst > ) ;
258
340
return ( ValueGetter < VBuffer < TDst > > ) ( ( ref VBuffer < TDst > dst ) =>
259
- {
260
- // The peek for a VBuffer is just a simple assignment, so there is
261
- // no copy going on in the peek, so we must do that as a second
262
- // step to the destination.
263
- peek ( GetCurrentRowObject ( ) , Position , ref buf ) ;
264
- buf . CopyTo ( ref dst ) ;
265
- } ) ;
341
+ {
342
+ // The peek for a VBuffer is just a simple assignment, so there is
343
+ // no copy going on in the peek, so we must do that as a second
344
+ // step to the destination.
345
+ peek ( GetCurrentRowObject ( ) , Position , ref buf ) ;
346
+ buf . CopyTo ( ref dst ) ;
347
+ } ) ;
266
348
}
267
349
268
- private Delegate CreateDirectGetter < TDst > ( int index )
350
+ private Delegate CreateDirectGetterDelegate < TDst > ( int index )
269
351
{
270
352
var peek = DataView . _peeks [ index ] as Peek < TRow , TDst > ;
271
353
Ch . AssertValue ( peek ) ;
272
- return ( ValueGetter < TDst > ) ( ( ref TDst dst ) => { peek ( GetCurrentRowObject ( ) , Position , ref dst ) ; } ) ;
354
+ return ( ValueGetter < TDst > ) ( ( ref TDst dst ) =>
355
+ {
356
+ peek ( GetCurrentRowObject ( ) , Position , ref dst ) ;
357
+ } ) ;
273
358
}
274
359
275
360
protected abstract TRow GetCurrentRowObject ( ) ;
0 commit comments