Skip to content

Commit 00000d9

Browse files
committed
typedefof is faster than StartsWith comparison
Array.CreateInstance is faster than Activator.CreateInstance<array>
1 parent f7b3435 commit 00000d9

7 files changed

Lines changed: 77 additions & 64 deletions

File tree

paket.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1501,7 +1501,7 @@ GITHUB
15011501
src/ProvidedTypes.fs (3b22420be5eddecaee89105d208cc4fb7b2e4df3)
15021502
src/ProvidedTypes.fsi (3b22420be5eddecaee89105d208cc4fb7b2e4df3)
15031503
remote: Thorium/Linq.Expression.Optimizer
1504-
src/Code/ExpressionOptimizer.fs (c539b8e0195c2ba747c436bb818cc305471daf07)
1504+
src/Code/ExpressionOptimizer.fs (de8cbb7aa89944cdd02cd4d197047badaf7cca3f)
15051505
GROUP Tests
15061506
STORAGE: PACKAGES
15071507
NUGET

src/SQLProvider.Common/SqlRuntime.Common.fs

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ type SqlEntity(dc: ISqlDataContext, tableName, columns: ColumnLookup, activeColu
362362
[|
363363
for prop in fields do
364364
match dataMap.TryGetValue(clean prop) with
365-
| true, null when prop.PropertyType.Name.StartsWith "FSharpValueOption" ->
365+
| true, null when Utilities.isVOpt prop.PropertyType ->
366366
#if NETSTANDARD21
367367
let typedNone = System.Runtime.CompilerServices.RuntimeHelpers.GetUninitializedObject prop.PropertyType
368368
#else
@@ -377,7 +377,7 @@ type SqlEntity(dc: ISqlDataContext, tableName, columns: ColumnLookup, activeColu
377377
let instance = Activator.CreateInstance<'a>()
378378
for prop in typ.GetProperties() do
379379
match dataMap.TryGetValue(clean prop) with
380-
| true, null when prop.PropertyType.Name.StartsWith "FSharpValueOption" ->
380+
| true, null when Utilities.isVOpt prop.PropertyType ->
381381
#if NETSTANDARD21
382382
let typedNone = System.Runtime.CompilerServices.RuntimeHelpers.GetUninitializedObject prop.PropertyType
383383
#else
@@ -1001,15 +1001,15 @@ module public OfflineTools =
10011001

10021002
let columnNames =
10031003
tableItem.GetProperties()
1004-
|> Array.map(fun col -> col.Name, col.PropertyType.Name)
1004+
|> Array.map(fun col -> col.Name, col.PropertyType.Name, Utilities.isOpt col.PropertyType)
10051005

1006-
let cols = columnNames |> Array.map(fun (nam,typ) ->
1006+
let cols = columnNames |> Array.map(fun (nam,typ, isOpt) ->
10071007
let tempCol = { Name = nam
10081008
TypeMapping = TypeMapping.Create(typ); IsPrimaryKey = false
1009-
IsNullable = String.IsNullOrEmpty typ || typ.StartsWith "FSharpOptio" || typ.StartsWith "FSharpValueOption"
1009+
IsNullable = String.IsNullOrEmpty typ || isOpt
10101010
IsAutonumber = false; HasDefault = false; IsComputed = false; TypeInfo = ValueNone }
10111011
nam, tempCol) |> ColumnLookup
1012-
columnNames, cols
1012+
columnNames |> Array.map(fun (f,_,_) -> f), cols
10131013

10141014

10151015
let internal createMockEntitiesDc<'T when 'T :> SqlEntity> dc (tableName:string) (dummydata: obj) =
@@ -1018,22 +1018,27 @@ module public OfflineTools =
10181018
dummydata :?> seq<obj>
10191019
|> Seq.map(fun row ->
10201020
let entity = SqlEntity(dc, tableName, cols, cols.Count)
1021-
for (col, _) in columnNames do
1021+
for col in columnNames do
10221022
let colProp = row.GetType().GetProperty(col)
10231023
let colData = if isNull colProp then null else colProp.GetValue(row, null)
1024-
let typ = if isNull colData || isNull (colData.GetType()) then "" else colData.GetType().Name
1025-
if typ.StartsWith "FSharpOptio" || typ.StartsWith "FSharpValueOption" then
1026-
let noneProp = colData.GetType().GetProperty("IsNone")
1024+
let typ, isOpt =
1025+
if isNull colData then null, false
1026+
else
1027+
let typ = colData.GetType()
1028+
if isNull typ then null, false
1029+
else typ, Utilities.isOpt typ
1030+
if isOpt then
1031+
let noneProp = typ.GetProperty("IsNone")
10271032
let optIsNone =
10281033
if isNull noneProp then null
10291034
elif noneProp.GetIndexParameters().Length = 0 then
1030-
colData.GetType().GetProperty("IsNone").GetValue(colData, null)
1035+
typ.GetProperty("IsNone").GetValue(colData, null)
10311036
else
1032-
isNull (colData.GetType().GetProperty "Value")
1037+
isNull (typ.GetProperty "Value")
10331038
if (isNull optIsNone) || optIsNone = true then
10341039
entity.SetColumnOptionSilent(col, None)
10351040
else
1036-
let optValProp = colData.GetType().GetProperty("Value")
1041+
let optValProp = typ.GetProperty("Value")
10371042
if isNull optValProp then
10381043
entity.SetColumnOptionSilent(col, None)
10391044
else

src/SQLProvider.Common/SqlRuntime.Linq.fs

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -77,16 +77,23 @@ module internal QueryImplementation =
7777
let genArgs = src.GetType().GetGenericArguments()
7878
if genArgs.Length <> 1 then None, None
7979
else
80-
let tRes = typedefof<ResizeArray<_>>.MakeGenericType genArgs.[0]
80+
let tTyp = genArgs.[0]
8181
Some svc, Some (fun (queryResultsourcePropertyReplacement : IEnumerable) ->
82+
let count =
83+
match queryResultsourcePropertyReplacement with
84+
| :? System.Collections.ICollection as ic -> ic.Count
85+
| _ ->
86+
let mutable count = 0
87+
for obj in queryResultsourcePropertyReplacement do
88+
count <- count + 1
89+
count
8290
let enu2 = queryResultsourcePropertyReplacement.GetEnumerator()
83-
let arr = Activator.CreateInstance(tRes, [||])
84-
let addMethod = arr.GetType().GetMethod "Add"
91+
let arr = Array.CreateInstance(tTyp, count)
92+
let mutable i = 0
8593
while enu2.MoveNext() do
86-
addMethod.Invoke(arr, [| enu2.Current |]) |> ignore
87-
94+
arr.SetValue(enu2.Current, i)
95+
i <- i + 1
8896
srcProp.SetValue(enu, (box arr))
89-
9097
)
9198
| _ -> None, None
9299
| _ -> None, None
@@ -107,7 +114,8 @@ module internal QueryImplementation =
107114
let invoker = projector :?> Func<SqlEntity, _> in seq { for e in results -> invoker.Invoke(e) } |> Seq.cache :> System.Collections.IEnumerable
108115
else
109116

110-
let isValueOption = (returnType.Name.StartsWith("ValueOption") || returnType.Name.StartsWith("FSharpValueOption")) && returnType.GenericTypeArguments.Length = 1
117+
let isValueOption = Utilities.isVOpt returnType && returnType.GenericTypeArguments.Length = 1
118+
111119
if isValueOption then
112120
if Type.(=)(returnType, typeof<ValueOption<String>>) then let invoker = projector :?> Func<SqlEntity, ValueOption<String>> in seq { for e in results -> invoker.Invoke(e) } |> Seq.cache :> System.Collections.IEnumerable
113121
elif Type.(=)(returnType, typeof<ValueOption<Decimal>>) then let invoker = projector :?> Func<SqlEntity, ValueOption<Decimal>> in seq { for e in results -> invoker.Invoke(e) } |> Seq.cache :> System.Collections.IEnumerable
@@ -154,8 +162,8 @@ module internal QueryImplementation =
154162
let inline internal parseGroupByQueryResults (projector:Delegate) (results:SqlEntity[]) =
155163
#endif
156164
let args = projector.GetType().GenericTypeArguments
157-
let keyType, keyConstructor, itemEntityType =
158-
if args.[0].Name.StartsWith("IGrouping") then
165+
let keyType, keyConstructor, itemEntityType =
166+
if Common.Utilities.isGrp args.[0] then
159167
if args.[0].GenericTypeArguments.Length = 0 then None, None, typeof<SqlEntity>
160168
else
161169
let kt = args.[0].GenericTypeArguments.[0]
@@ -166,7 +174,7 @@ module internal QueryImplementation =
166174
Some kt, Some (tyo.GetConstructors()), itmType
167175
else
168176
let baseItmType = typeof<Microsoft.FSharp.Linq.RuntimeHelpers.AnonymousObject<SqlEntity,SqlEntity>>
169-
let genOpt = args.[0].GenericTypeArguments |> Array.tryFind(fun a -> a.Name.StartsWith("IGrouping"))
177+
let genOpt = args.[0].GenericTypeArguments |> Array.tryFind Common.Utilities.isGrp
170178
match genOpt with
171179
| None ->
172180
// GroupValBy
@@ -1102,7 +1110,7 @@ module internal QueryImplementation =
11021110

11031111
| MethodCall(None, (MethodWithName "Select"), [ SourceWithQueryData source; OptionalQuote (Lambda([ v1 ], _) as lambda) ]) as whole ->
11041112
let ty = typedefof<SqlQueryable<_>>.MakeGenericType((lambda :?> LambdaExpression).ReturnType )
1105-
if v1.Name.StartsWith "_arg" && Type.(<>)(v1.Type, typeof<SqlEntity>) && not(v1.Type.Name.StartsWith("IGrouping")) then
1113+
if v1.Name.StartsWith "_arg" && Type.(<>)(v1.Type, typeof<SqlEntity>) && not(Utilities.isGrp v1.Type) then
11061114
// this is the projection from a join - ignore
11071115
// causing the ignore here will give us wrong return tyoe to deal with in convertExpression lambda handling
11081116
ty.GetConstructors().[0].Invoke [| source.DataContext; source.Provider; source.SqlExpression; source.TupleIndex; |] :?> IQueryable<_>

src/SQLProvider.Common/SqlRuntime.Patterns.fs

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,7 @@ let inline (|OptionNone|_|) (e: Expression) =
143143
match e with
144144
| MethodCall(None,MethodWithName("get_None"),[]) ->
145145
match e with
146-
| :? MethodCallExpression as e when (e.Method.DeclaringType.FullName.StartsWith("Microsoft.FSharp.Core.FSharpOption`1")
147-
|| e.Method.DeclaringType.FullName.StartsWith("Microsoft.FSharp.Core.FSharpValueOption`1")) -> ValueSome()
146+
| :? MethodCallExpression as e when Common.Utilities.isOpt e.Method.DeclaringType -> ValueSome()
148147
| _ -> ValueNone
149148
| _ -> ValueNone
150149

@@ -157,8 +156,7 @@ let (|NullConstant|_|) (e:Expression) =
157156
let (|ConstantOrNullableConstant|_|) (e:Expression) =
158157
match e.NodeType, e with
159158
| ExpressionType.Constant, (:? ConstantExpression as ce) ->
160-
if ce.Type.IsGenericType && (ce.Type.FullName.StartsWith("Microsoft.FSharp.Core.FSharpOption`1")
161-
|| ce.Type.FullName.StartsWith("Microsoft.FSharp.Core.FSharpValueOption`1")) then
159+
if Common.Utilities.isOpt ce.Type then
162160
match ce.Type.GetProperty("Value").GetValue(ce.Value,[||]) with
163161
| null -> Some(Some(ce.Value))
164162
| optVal -> Some(Some(optVal))
@@ -223,11 +221,10 @@ let (|OptionalFSharpOptionValue|) (e:Expression) =
223221
match e.NodeType, e with
224222
| ExpressionType.MemberAccess, ( :? MemberExpression as e) ->
225223
match e.Member with
226-
| :? PropertyInfo as p when p.Name = "Value" && (e.Member.DeclaringType.FullName.StartsWith("Microsoft.FSharp.Core.FSharpOption`1")
227-
|| e.Member.DeclaringType.FullName.StartsWith("Microsoft.FSharp.Core.FSharpValueOption`1")) -> e.Expression
224+
| :? PropertyInfo as p when p.Name = "Value" && Common.Utilities.isOpt e.Member.DeclaringType -> e.Expression
228225
| _ -> upcast e
229226
| ExpressionType.Call, OptionalCopyOfStruct ( :? MethodCallExpression as e)
230-
when e.Method.Name = "Some" && (e.Method.DeclaringType.FullName.StartsWith("Microsoft.FSharp.Core.FSharpOption`1") || e.Method.DeclaringType.FullName.StartsWith("Microsoft.FSharp.Core.FSharpValueOption`1")) -> e.Arguments.[0]
227+
when e.Method.Name = "Some" && Common.Utilities.isOpt e.Method.DeclaringType -> e.Arguments.[0]
231228
| _, OptionalCopyOfStruct n -> n
232229

233230
let (|AndAlso|_|) (e:Expression) =
@@ -367,8 +364,8 @@ let integerTypes = [| typeof<Int32>; typeof<Int64>; typeof<Int16>; typeof<int8>;
367364
typeof<ValueOption<Int32>>; typeof<ValueOption<Int64>>; typeof<ValueOption<Int16>>; typeof<ValueOption<int8>>; typeof<ValueOption<UInt32>>; typeof<ValueOption<UInt64>>; typeof<ValueOption<UInt16>>; typeof<ValueOption<uint8>>;|]
368365

369366
let intType (typ:Type) =
370-
if (not (isNull typ)) && typ.IsGenericType && typ.GetGenericTypeDefinition() = typedefof<Option<_>> then typeof<Option<int>>
371-
elif (not (isNull typ)) && typ.IsGenericType && typ.GetGenericTypeDefinition() = typedefof<ValueOption<_>> then typeof<ValueOption<int>>
367+
if (not (isNull typ)) && Common.Utilities.isCOpt typ then typeof<Option<int>>
368+
elif (not (isNull typ)) && Common.Utilities.isVOpt typ then typeof<ValueOption<int>>
372369
else typeof<int>
373370

374371
let inline internal getRightFromOp (right:Expression) =
@@ -396,13 +393,13 @@ let rec (|SqlColumnGet|_|) (ex:Expression) =
396393
// These are aggregations, e.g. GROUPBY, HAVING-clause
397394
| ExpressionType.MemberAccess, ( :? MemberExpression as me) when
398395
(not (isNull me.Expression || isNull me.Expression.Type || isNull me.Expression.Type.Name)) &&
399-
me.Expression.Type.Name.StartsWith("IGrouping") ->
396+
Common.Utilities.isGrp me.Expression.Type ->
400397
match me.Member with
401398
| :? PropertyInfo as p when p.Name = "Key" -> Some(String.Empty, GroupColumn (KeyOp "",SqlColumnType.KeyColumn("Key")), p.DeclaringType)
402399
| _ -> None
403400
| ExpressionType.Call, ( :? MethodCallExpression as e) when (not (isNull e.Arguments)) && e.Arguments.Count = 1 &&
404401
not( isNull e.Arguments.[0] || isNull e.Arguments.[0].Type || isNull e.Arguments.[0].Type.Name) &&
405-
e.Arguments.[0].Type.Name.StartsWith("IGrouping") ->
402+
Common.Utilities.isGrp e.Arguments.[0].Type ->
406403
if e.Arguments.[0].NodeType = ExpressionType.Parameter then
407404
let pn = match e.Arguments.[0] with :? ParameterExpression as p -> p.Name | _ -> e.Method.Name
408405
match e.Method.Name with
@@ -566,7 +563,7 @@ let rec (|SqlColumnGet|_|) (ex:Expression) =
566563

567564
match be.Left, be.Right with
568565
| OptionalConvertOrTypeAs(OptionalFSharpOptionValue(SqlColumnGet(alias, col, typ))) as p1, OptionalConvertOrTypeAs(Constant(constVal,constTyp))
569-
when (Type.(=)(p1.Type, constTyp) || (p1.Type.IsGenericType && (p1.Type.GetGenericTypeDefinition() = typedefof<Option<_>> || p1.Type.GetGenericTypeDefinition() = typedefof<ValueOption<_>>) && p1.Type.GenericTypeArguments.[0] = constTyp )
566+
when (Type.(=)(p1.Type, constTyp) || (Common.Utilities.isOpt p1.Type && p1.Type.GenericTypeArguments.[0] = constTyp )
570567
|| Type.(=)(be.Left.Type, be.Right.Type)) -> // Support only numeric and string math
571568
match p1.Type with
572569
| t when (operation = "+" && (Type.(=)(t, typeof<System.String>) || Type.(=)(t, typeof<System.Char>) || Type.(=)(t, typeof<Option<System.String>>) || Type.(=)(t, typeof<Option<System.Char>>) || Type.(=)(t, typeof<ValueOption<System.Char>>))) ->
@@ -576,7 +573,7 @@ let rec (|SqlColumnGet|_|) (ex:Expression) =
576573
Some(alias, CanonicalOperation(CanonicalOp.BasicMath(operation, constVal), col), typ)
577574
| _ -> None
578575
| OptionalConvertOrTypeAs(Constant(constVal,constTyp)), (OptionalConvertOrTypeAs(OptionalFSharpOptionValue(SqlColumnGet(alias, col, typ))) as p1)
579-
when (Type.(=)(p1.Type, constTyp) || (p1.Type.IsGenericType && (p1.Type.GetGenericTypeDefinition() = typedefof<Option<_>> || p1.Type.GetGenericTypeDefinition() = typedefof<ValueOption<_>>) && p1.Type.GenericTypeArguments.[0] = constTyp )
576+
when (Type.(=)(p1.Type, constTyp) || (Common.Utilities.isOpt p1.Type && p1.Type.GenericTypeArguments.[0] = constTyp )
580577
|| Type.(=)(be.Left.Type, be.Right.Type)) -> // Support only numeric and string math
581578
match p1.Type with
582579
| t when (operation = "+" && (Type.(=)(t, typeof<System.String>) || Type.(=)(t, typeof<System.Char>) || Type.(=)(t, typeof<Option<System.String>>) || Type.(=)(t, typeof<Option<System.Char>>) || Type.(=)(t, typeof<ValueOption<System.String>>) || Type.(=)(t, typeof<ValueOption<System.Char>>))) ->
@@ -587,8 +584,8 @@ let rec (|SqlColumnGet|_|) (ex:Expression) =
587584
| _ -> None
588585
| OptionalConvertOrTypeAs(OptionalFSharpOptionValue(SqlColumnGet(aliasLeft, colLeft, typLeft))) as p1, (OptionalConvertOrTypeAs(OptionalFSharpOptionValue(SqlColumnGet(aliasRight, colRight, typRight))) as p2)
589586
when (Type.(=)(p1.Type, p2.Type) ||
590-
(p1.Type.IsGenericType && (p1.Type.GetGenericTypeDefinition() = typedefof<Option<_>> || p1.Type.GetGenericTypeDefinition() = typedefof<ValueOption<_>>) && p1.Type.GenericTypeArguments.[0] = p2.Type ) ||
591-
(p2.Type.IsGenericType && (p2.Type.GetGenericTypeDefinition() = typedefof<Option<_>> || p2.Type.GetGenericTypeDefinition() = typedefof<ValueOption<_>>) && p2.Type.GenericTypeArguments.[0] = p1.Type ) ||
587+
(Common.Utilities.isOpt p1.Type && p1.Type.GenericTypeArguments.[0] = p2.Type ) ||
588+
(Common.Utilities.isOpt p2.Type && p2.Type.GenericTypeArguments.[0] = p1.Type ) ||
592589
Type.(=)(be.Left.Type, be.Right.Type)) ->
593590
let opFix =
594591
match p1.Type with
@@ -733,8 +730,7 @@ and (|SimpleCondition|_|) exp =
733730
if isNull invokedResult then handleNullCompare()
734731
else
735732
let retType = invokedResult.GetType()
736-
if retType.IsGenericType && (retType.FullName.StartsWith("Microsoft.FSharp.Core.FSharpOption") ||
737-
retType.FullName.StartsWith("Microsoft.FSharp.Core.FSharpValueOption")) then
733+
if Common.Utilities.isOpt retType then
738734
let gotVal = retType.GetProperty("Value") // Option type Some should not be SQL-parameter.
739735
match gotVal.GetValue(invokedResult, [||]) with
740736
| null -> handleNullCompare()

0 commit comments

Comments
 (0)