diff --git a/src/fsharp/FSharp.Core/string.fs b/src/fsharp/FSharp.Core/string.fs index d009615e6aa..5c8f15ba717 100644 --- a/src/fsharp/FSharp.Core/string.fs +++ b/src/fsharp/FSharp.Core/string.fs @@ -52,13 +52,19 @@ namespace Microsoft.FSharp.Core [] let mapi (mapping: int -> char -> char) (str:string) = - if String.IsNullOrEmpty str then + let len = length str + if len = 0 then String.Empty else - let res = StringBuilder str.Length + let result = str.ToCharArray() let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(mapping) - str |> iteri (fun i c -> res.Append(f.Invoke(i, c)) |> ignore) - res.ToString() + + let mutable i = 0 + while i < len do + result.[i] <- f.Invoke(i, result.[i]) + i <- i + 1 + + new String(result) [] let filter (predicate: char -> bool) (str:string) = diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/StringModule.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/StringModule.fs index 6c1b1360585..5470b6dece6 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/StringModule.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/StringModule.fs @@ -103,11 +103,35 @@ type StringModule() = [] member this.MapI() = - let e1 = String.mapi (fun i c -> char(int c + i)) "foo" - Assert.AreEqual("fpq", e1) + let e1 = String.mapi (fun _ c -> c) "12345" + Assert.AreEqual("12345", e1) - let e2 = String.mapi (fun i c -> c) null - Assert.AreEqual("", e2) + let e2 = String.mapi (fun _ c -> c + char 1) "1" + Assert.AreEqual("2", e2) + + let e3 = String.mapi (fun _ c -> c + char 1) "AB" + Assert.AreEqual("BC", e3) + + let e4 = String.mapi (fun i c -> char(int c + i)) "hello" + Assert.AreEqual("hfnos", e4) + + let e5 = String.mapi (fun _ c -> c) null + Assert.AreEqual("", e5) + + let e6 = String.mapi (fun _ c -> c) String.Empty + Assert.AreEqual("", e6) + + let e7 = String.mapi (fun _ _ -> failwith "should not fail") null + Assert.AreEqual("", e7) + + let e8 = String.mapi (fun i _ -> if i = 1 then failwith "should not fail" else char i) "X" + Assert.AreEqual("\u0000", e8) + + // side-effect and "order of operation" test + let mutable x = 0 + let e9 = String.mapi (fun i c -> x <- x + i; c + char x) "abcde" + Assert.AreEqual(x, 10) + Assert.AreEqual(e9, "acfjo") [] member this.Filter() =