Skip to content

Commit

Permalink
Array-based List type
Browse files Browse the repository at this point in the history
  • Loading branch information
ncave committed Sep 11, 2020
1 parent 4eb00a2 commit 6a7ac3e
Show file tree
Hide file tree
Showing 14 changed files with 577 additions and 440 deletions.
4 changes: 2 additions & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,9 @@
"type": "coreclr",
"request": "launch",
"name": "bench-compile (.NET)",
"program": "${workspaceFolder}/src/fable-standalone/test/bench-compiler/bin/Debug/netcoreapp2.1/bench-compiler.dll",
"program": "${workspaceFolder}/src/fable-standalone/test/bench-compiler/bin/Debug/netcoreapp3.1/bench-compiler.dll",
// "args": ["${workspaceRoot}/tests/Main/Fable.Tests.fsproj", "out-tests", "--commonjs"],
"args": ["${workspaceRoot}/../fable-test/fable-test.fsproj", "out-test", "--typescript"],
"args": ["${workspaceRoot}/../fable-test/fable-test.fsproj", "out-test"],
"cwd": "${workspaceFolder}/src/fable-standalone/test/bench-compiler"
},
{
Expand Down
4 changes: 4 additions & 0 deletions src/Fable.Transforms/FSharp2Fable.Util.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1203,6 +1203,10 @@ module Util =
else
// Indexed properties keep the get_/set_ prefix and are compiled as methods
if indexedProp then memb.CompiledName, false, false
// performance optimization, compile get_Current as instance call instead of a getter
elif memb.FullName = "System.Collections.IEnumerator.get_Current" ||
memb.FullName = "System.Collections.Generic.IEnumerator.get_Current"
then getMemberDisplayName memb, false, false
else getMemberDisplayName memb, isGetter, isSetter
if isGetter then
let t = memb.ReturnParameter.Type |> makeType Map.empty
Expand Down
5 changes: 5 additions & 0 deletions src/Fable.Transforms/FSharp2Fable.fs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,11 @@ let private getAttachedMemberInfo com ctx r nonMangledNameConflicts
let name, isGetter, isSetter =
// For indexed properties, keep the get_/set_ prefix and compile as method
if indexedProp then sign.Name, false, false
// performance optimization, compile get_Current as instance call instead of a getter
elif sign.Name = "get_Current" &&
(fullName = Some "System.Collections.IEnumerator" ||
fullName = Some "System.Collections.Generic.IEnumerator`1")
then Naming.removeGetSetPrefix sign.Name, false, false
else Naming.removeGetSetPrefix sign.Name, isGetter, isSetter
// Setters can have same name as getters, assume there will always be a getter
if not isSetter && nonMangledNameConflicts declaringEntityName name then
Expand Down
35 changes: 18 additions & 17 deletions src/Fable.Transforms/Fable2Babel.fs
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ module Annotation =
makeNativeTypeAnnotation com ctx [genArg] "Array"

let makeListTypeAnnotation com ctx genArg =
makeImportTypeAnnotation com ctx [genArg] "Types" "List"
makeImportTypeAnnotation com ctx [genArg] "List" "List"

let makeUnionTypeAnnotation com ctx genArgs =
List.map (typeAnnotation com ctx) genArgs
Expand Down Expand Up @@ -655,12 +655,6 @@ module Util =
| [] -> expr
| m::ms -> get None expr m |> getParts ms

let makeList com ctx headAndTail =
match headAndTail with
| None -> [||]
| Some(TransformExpr com ctx head, TransformExpr com ctx tail) -> [|head; tail|]
|> libConsCall com ctx "Types" "List"

let makeArray (com: IBabelCompiler) ctx exprs =
List.mapToArray (fun e -> com.TransformAsExpr(ctx, e)) exprs
|> ArrayExpression :> Expression
Expand Down Expand Up @@ -893,12 +887,17 @@ module Util =
| Fable.NewTuple vals -> makeArray com ctx vals
// Optimization for bundle size: compile list literals as List.ofArray
| Replacements.ListLiteral(exprs, t) ->
match exprs with
| [] -> makeList com ctx None
| [expr] -> Some(expr, Fable.Value(Fable.NewList (None,t), None)) |> makeList com ctx
| exprs -> [|makeArray com ctx exprs|] |> libCall com ctx r "List" "ofArray"
[|List.rev exprs |> makeArray com ctx|]
|> libCall com ctx r "List" "newList"
// match exprs with
// | [] -> libCall com ctx r "List" "empty" [||]
// | [TransformExpr com ctx expr] -> libCall com ctx r "List" "singleton" [|expr|]
// | exprs -> [|makeArray com ctx exprs|] |> libCall com ctx r "List" "ofArray"
| Fable.NewList (headAndTail, _) ->
makeList com ctx headAndTail
match headAndTail with
| None -> libCall com ctx r "List" "empty" [||]
| Some(TransformExpr com ctx head, TransformExpr com ctx tail) ->
libCall com ctx r "List" "cons" [|head; tail|]
| Fable.NewOption (value, t) ->
match value with
| Some (TransformExpr com ctx e) ->
Expand Down Expand Up @@ -1086,8 +1085,10 @@ module Util =
match getKind with
| Fable.ByKey(Fable.ExprKey(TransformExpr com ctx prop)) -> getExpr range expr prop
| Fable.ByKey(Fable.FieldKey field) -> get range expr field.Name
| Fable.ListHead -> get range expr "head"
| Fable.ListTail -> get range expr "tail"
// | Fable.ListHead -> get range expr "Head"
// | Fable.ListTail -> get range expr "Tail"
| Fable.ListHead -> libCall com ctx range "List" "head" [|expr|]
| Fable.ListTail -> libCall com ctx range "List" "tail" [|expr|]
| Fable.TupleIndex index -> getExpr range expr (ofInt index)
| Fable.OptionValue ->
if mustWrapOption typ || com.Options.Typescript
Expand Down Expand Up @@ -1143,9 +1144,9 @@ module Util =
let op = if nonEmpty then BinaryUnequal else BinaryEqual
upcast BinaryExpression(op, com.TransformAsExpr(ctx, expr), NullLiteral(), ?loc=range)
| Fable.ListTest nonEmpty ->
let expr = com.TransformAsExpr(ctx, expr)
let op = if nonEmpty then BinaryUnequal else BinaryEqual
upcast BinaryExpression(op, get None expr "tail", NullLiteral(), ?loc=range)
// let expr = get range (com.TransformAsExpr(ctx, expr)) "IsEmpty"
let expr = libCall com ctx range "List" "isEmpty" [|com.TransformAsExpr(ctx, expr)|]
if nonEmpty then upcast UnaryExpression(UnaryNot, expr, ?loc=range) else expr
| Fable.UnionCaseTest tag ->
let expected = ofInt tag
let actual = com.TransformAsExpr(ctx, expr) |> getUnionExprTag None
Expand Down
35 changes: 17 additions & 18 deletions src/Fable.Transforms/Replacements.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1664,6 +1664,8 @@ let resizeArrays (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (this
Helper.LibCall(com, "Seq", "filter", t, [arg; ar], ?loc=r) |> toArray com t |> Some
| "AddRange", Some ar, [arg] ->
Helper.LibCall(com, "Array", "addRangeInPlace", t, [arg; ar], ?loc=r) |> Some
| "GetRange", Some ar, [idx; cnt] ->
Helper.LibCall(com, "Array", "getSubArray", t, [ar; idx; cnt], ?loc=r) |> Some
| "Contains", Some (MaybeCasted(ar)), [arg] ->
match ar.Type with
| Array _ ->
Expand Down Expand Up @@ -1771,29 +1773,26 @@ let arrayModule (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (_: Ex
Helper.LibCall(com, "Array", meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some

let lists (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (thisArg: Expr option) (args: Expr list) =
let meth = Naming.removeGetSetPrefix i.CompiledName |> Naming.lowerFirst
match i.CompiledName, thisArg, args with
// Use methods for Head and Tail (instead of Get(ListHead) for example) to check for empty lists
| ReplaceName
[ "get_Head", "head"
"get_Tail", "tail"
"get_Item", "item"
"get_Length", "length"
"GetSlice", "slice" ] methName, Some x, _ ->
let args = match args with [ExprType Unit] -> [x] | args -> args @ [x]
Helper.LibCall(com, "List", methName, t, args, i.SignatureArgTypes, ?loc=r) |> Some
| "get_IsEmpty", Some x, _ -> Test(x, ListTest false, r) |> Some
| "get_Empty", None, _ -> NewList(None, (genArg com ctx r 0 i.GenericArgs)) |> makeValue r |> Some
| "Cons", None, [h;t] -> NewList(Some(h,t), (genArg com ctx r 0 i.GenericArgs)) |> makeValue r |> Some
| ("get_Head" | "get_Tail" | "get_IsEmpty" | "get_Length"), Some x, _ ->
Helper.LibCall(com, "List", meth, t, [x], i.SignatureArgTypes, ?loc=r) |> Some
// get r t x meth |> Some
| ("get_Item" | "GetSlice"), Some x, _ ->
Helper.LibCall(com, "List", meth, t, args @ [x], i.SignatureArgTypes, ?loc=r) |> Some
| ("get_Empty" | "Cons"), None, _ ->
Helper.LibCall(com, "List", meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some
| ("GetHashCode" | "Equals" | "CompareTo"), Some callee, _ ->
Helper.InstanceCall(callee, i.CompiledName, t, args, i.SignatureArgTypes, ?loc=r) |> Some
| _ -> None

let listModule (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (_: Expr option) (args: Expr list) =
match i.CompiledName, args with
| "IsEmpty", [x] -> Test(x, ListTest false, r) |> Some
| "Empty", _ -> NewList(None, (genArg com ctx r 0 i.GenericArgs)) |> makeValue r |> Some
| "Singleton", [x] ->
NewList(Some(x, Value(NewList(None, t), None)), (genArg com ctx r 0 i.GenericArgs)) |> makeValue r |> Some
// | ("Head" | "Tail" | "IsEmpty") as meth, [x] -> get r t x (Naming.lowerFirst meth) |> Some
// | "IsEmpty", [x] -> Test(x, ListTest false, r) |> Some
// | "Empty", _ -> NewList(None, (genArg com ctx r 0 i.GenericArgs)) |> makeValue r |> Some
// | "Singleton", [x] ->
// NewList(Some(x, Value(NewList(None, t), None)), (genArg com ctx r 0 i.GenericArgs)) |> makeValue r |> Some
// Use a cast to give it better chances of optimization (e.g. converting list
// literals to arrays) after the beta reduction pass
| "ToSeq", [x] -> toSeq t x |> Some
Expand Down Expand Up @@ -2586,8 +2585,8 @@ let enumerables (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr

let enumerators (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (thisArg: Expr option) (args: Expr list) =
match i.CompiledName, thisArg with
| "get_Current", Some x -> get r t x "Current" |> Some
| meth, Some x -> Helper.InstanceCall(x, meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some
// | "get_Current", Some x -> get r t x "Current" |> Some
| meth, Some x -> Helper.InstanceCall(x, Naming.removeGetSetPrefix meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some
| _ -> None

let events (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (thisArg: Expr option) (args: Expr list) =
Expand Down
13 changes: 6 additions & 7 deletions src/fable-library/Array.fs
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,7 @@ module Helpers =

open Helpers

let private indexNotFound() =
failwith "An index satisfying the predicate was not found in the collection."
let private indexNotFoundMsg = "An index satisfying the predicate was not found in the collection."

// Pay attention when benchmarking to append and filter functions below
// if implementing via native JS array .concat() and .filter() do not fall behind due to js-native transitions.
Expand Down Expand Up @@ -445,15 +444,15 @@ let partition (f: 'T -> bool) (source: 'T[]) ([<Inject>] cons: IArrayCons<'T>) =
let find (predicate: 'T -> bool) (array: 'T[]): 'T =
match findImpl predicate array with
| Some res -> res
| None -> indexNotFound()
| None -> failwith indexNotFoundMsg

let tryFind (predicate: 'T -> bool) (array: 'T[]): 'T option =
findImpl predicate array

let findIndex (predicate: 'T -> bool) (array: 'T[]): int =
match findIndexImpl predicate array with
| index when index > -1 -> index
| _ -> indexNotFound()
| _ -> failwith indexNotFoundMsg

let tryFindIndex (predicate: 'T -> bool) (array: 'T[]): int option =
match findIndexImpl predicate array with
Expand All @@ -463,7 +462,7 @@ let tryFindIndex (predicate: 'T -> bool) (array: 'T[]): int option =
let pick chooser (array: _[]) =
let rec loop i =
if i >= array.Length then
indexNotFound()
failwith indexNotFoundMsg
else
match chooser array.[i] with
| None -> loop(i+1)
Expand All @@ -480,7 +479,7 @@ let tryPick chooser (array: _[]) =

let findBack predicate (array: _[]) =
let rec loop i =
if i < 0 then indexNotFound()
if i < 0 then failwith indexNotFoundMsg
elif predicate array.[i] then array.[i]
else loop (i - 1)
loop (array.Length - 1)
Expand All @@ -501,7 +500,7 @@ let findLastIndex predicate (array: _[]) =

let findIndexBack predicate (array: _[]) =
let rec loop i =
if i < 0 then indexNotFound()
if i < 0 then failwith indexNotFoundMsg
elif predicate array.[i] then i
else loop (i - 1)
loop (array.Length - 1)
Expand Down
Loading

0 comments on commit 6a7ac3e

Please sign in to comment.