Skip to content

Commit 3a91ebc

Browse files
committed
Using known length for mapping, and unrolling x2 to improve perf of String.mapi by 2.5x
1 parent c777c6a commit 3a91ebc

File tree

1 file changed

+16
-5
lines changed

1 file changed

+16
-5
lines changed

src/fsharp/FSharp.Core/string.fs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,24 @@ namespace Microsoft.FSharp.Core
4343

4444
[<CompiledName("MapIndexed")>]
4545
let mapi (mapping: int -> char -> char) (str:string) =
46-
if String.IsNullOrEmpty str then
46+
let len = length str
47+
if len = 0 then
4748
String.Empty
4849
else
49-
let res = StringBuilder str.Length
50-
let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(mapping)
51-
str |> iteri (fun i c -> res.Append(f.Invoke(i, c)) |> ignore)
52-
res.ToString()
50+
let result = str.ToCharArray()
51+
let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt mapping
52+
53+
// x2 unrolled loop gives 10-20% boost, overall 2.5x SB perf
54+
let mutable i = 0
55+
while i < len - len % 2 do
56+
result.[i] <- f.Invoke(i, result.[i])
57+
result.[i + 1] <- f.Invoke(i, result.[i + 1])
58+
i <- i + 2
59+
60+
if i % 2 = 1 then
61+
result.[i] <- f.Invoke(i, result.[i])
62+
63+
new String(result)
5364

5465
[<CompiledName("Filter")>]
5566
let filter (predicate: char -> bool) (str:string) =

0 commit comments

Comments
 (0)