Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f9f76d9

Browse files
authored
Span<T> F# snippets (#7851)
1 parent 5d52752 commit f9f76d9

File tree

11 files changed

+279
-0
lines changed

11 files changed

+279
-0
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
module Program
2+
3+
open System
4+
open System.Threading.Tasks
5+
6+
let array = Array.zeroCreate<byte> 5
7+
8+
let clearContents () =
9+
Task.Delay(20).Wait()
10+
lock array (fun () ->
11+
Array.Clear(array, 0, array.Length) )
12+
13+
let enumerateSpan (span: Span<byte>) =
14+
for element in span do
15+
printfn $"{element}"
16+
Task.Delay(10).Wait()
17+
18+
[<EntryPoint>]
19+
let main _ =
20+
Random(42).NextBytes array
21+
printfn "%A" array
22+
let span: Span<byte> = array
23+
24+
Task.Run clearContents |> ignore
25+
26+
enumerateSpan span
27+
28+
0
29+
30+
// The example displays output like the following:
31+
// 62
32+
// 23
33+
// 186
34+
// 0
35+
// 0
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
module Program2
2+
3+
open System
4+
open System.Threading
5+
open System.Threading.Tasks
6+
7+
let array = Array.zeroCreate<byte> 5
8+
9+
// <Snippet1>
10+
let enumerateSpan (span: Span<byte>) =
11+
// Spans cannot be accessed in closures including in the F# lock function.
12+
// Monitor.Enter and Monitor.Exit are used here directly.
13+
Monitor.Enter array
14+
try
15+
for element in span do
16+
printfn $"{element}"
17+
Task.Delay(10).Wait()
18+
finally
19+
Monitor.Exit array
20+
// The example displays the following output:
21+
// 62
22+
// 23
23+
// 186
24+
// 150
25+
// 174
26+
// </Snippet1>
27+
28+
let clearContents () =
29+
Task.Delay(20).Wait()
30+
lock array (fun () ->
31+
Array.Clear(array, 0, array.Length) )
32+
33+
[<EntryPoint>]
34+
let main _ =
35+
Random(42).NextBytes array
36+
let span: Span<byte> = array
37+
38+
Task.Run clearContents |> ignore
39+
40+
enumerateSpan span
41+
42+
0
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<OutputType>Exe</OutputType>
4+
<TargetFramework>net6.0</TargetFramework>
5+
</PropertyGroup>
6+
7+
<ItemGroup>
8+
<Compile Include="..\Program2.fs" />
9+
</ItemGroup>
10+
</Project>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<OutputType>Exe</OutputType>
4+
<TargetFramework>net6.0</TargetFramework>
5+
</PropertyGroup>
6+
7+
<ItemGroup>
8+
<Compile Include="Program.fs" />
9+
</ItemGroup>
10+
</Project>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<OutputType>Exe</OutputType>
4+
<TargetFramework>net6.0</TargetFramework>
5+
</PropertyGroup>
6+
7+
<ItemGroup>
8+
<Compile Include="program.fs" />
9+
</ItemGroup>
10+
</Project>
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
open System
2+
open System.Runtime.InteropServices
3+
4+
let createSpanFromArray () =
5+
// <Snippet1>
6+
// Create a span over an array.
7+
let array = Array.zeroCreate<byte> 100
8+
let arraySpan = Span<byte> array
9+
10+
let mutable data = 0uy
11+
for i = 0 to arraySpan.Length - 1 do
12+
arraySpan[i] <- data
13+
data <- data + 1uy
14+
15+
let mutable arraySum = 0
16+
for value in array do
17+
arraySum <- arraySum + int value
18+
19+
printfn $"The sum is {arraySum}"
20+
// Output: The sum is 4950
21+
// </Snippet1>
22+
23+
let createSpanFromNativeMemory () =
24+
// <Snippet2>
25+
// Create a span from native memory.
26+
let native = Marshal.AllocHGlobal 100
27+
let nativeSpan = Span<byte>(native.ToPointer(), 100)
28+
29+
let mutable data = 0uy
30+
for i = 0 to nativeSpan.Length - 1 do
31+
nativeSpan[i] <- data
32+
data <- data + 1uy
33+
34+
let mutable nativeSum = 0
35+
for value in nativeSpan do
36+
nativeSum <- nativeSum + int value
37+
38+
printfn $"The sum is {nativeSum}"
39+
Marshal.FreeHGlobal native
40+
// Output: The sum is 4950
41+
// </Snippet2>
42+
43+
let createSpanFromStack () =
44+
// <Snippet3>
45+
// Create a span on the stack.
46+
let mutable data = 0uy
47+
let stackSpan =
48+
let p = NativeInterop.NativePtr.stackalloc<byte> 100 |> NativeInterop.NativePtr.toVoidPtr
49+
Span<byte>(p, 100)
50+
51+
for i = 0 to stackSpan.Length - 1 do
52+
stackSpan[i] <- data
53+
data <- data + 1uy
54+
55+
let mutable stackSum = 0
56+
for value in stackSpan do
57+
stackSum <- stackSum + int value
58+
59+
printfn $"The sum is {stackSum}"
60+
// Output: The sum is 4950
61+
// </Snippet3>
62+
63+
module Program2 =
64+
// <Snippet4>
65+
open System
66+
open System.Runtime.InteropServices
67+
open FSharp.NativeInterop
68+
69+
// Package FSharp.NativeInterop.NativePtr.stackalloc for reuse.
70+
let inline stackalloc<'a when 'a: unmanaged> length : Span<'a> =
71+
let voidPointer = NativePtr.stackalloc<'a> length |> NativePtr.toVoidPtr
72+
Span<'a>(voidPointer, length)
73+
74+
let initializeSpan (span: Span<byte>) =
75+
let mutable value = 0uy
76+
for i = 0 to span.Length - 1 do
77+
span[i] <- value
78+
value <- value + 1uy
79+
80+
let computeSum (span: Span<byte>) =
81+
let mutable sum = 0
82+
for value in span do
83+
sum <- sum + int value
84+
sum
85+
86+
let workWithSpans () =
87+
// Create a span over an array.
88+
let array = Array.zeroCreate<byte> 100
89+
let arraySpan = Span<byte> array
90+
91+
initializeSpan arraySpan
92+
printfn $"The sum is {computeSum arraySpan:N0}"
93+
94+
// Create an array from native memory.
95+
let native = Marshal.AllocHGlobal 100
96+
let nativeSpan = Span<byte>(native.ToPointer(), 100)
97+
98+
initializeSpan nativeSpan
99+
printfn $"The sum is {computeSum nativeSpan:N0}"
100+
101+
Marshal.FreeHGlobal native
102+
103+
// Create a span on the stack.
104+
let stackSpan = stackalloc 100
105+
106+
initializeSpan stackSpan
107+
printfn $"The sum is {computeSum stackSpan:N0}"
108+
109+
// The example displays the following output:
110+
// The sum is 4,950
111+
// The sum is 4,950
112+
// The sum is 4,950
113+
// </Snippet4>
114+
115+
createSpanFromArray ()
116+
printfn "-----"
117+
createSpanFromNativeMemory ()
118+
printfn "-----"
119+
createSpanFromStack ()
120+
printfn "-----"
121+
Program2.workWithSpans ()
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
module Program
2+
3+
open System
4+
5+
[<EntryPoint>]
6+
let main _ =
7+
let array = [| 2; 4; 6; 8; 10; 12; 14; 16; 18; 20 |]
8+
let slice = Span<int>(array, 2, 5)
9+
for i = 0 to slice.Length - 1 do
10+
slice[i] <- slice[i] * 2
11+
12+
// Examine the original array values.
13+
for value in array do
14+
printf $"{value} "
15+
printfn ""
16+
0
17+
// The example displays the following output:
18+
// 2 4 12 16 20 24 28 16 18 20
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
module Program2
2+
3+
open System
4+
5+
let getContentLength (span: ReadOnlySpan<char>) =
6+
let slice = span.Slice 16
7+
Int32.Parse slice
8+
9+
let contentLength = "Content-Length: 132"
10+
let length = getContentLength (contentLength.ToCharArray())
11+
printfn $"Content length: {length}"
12+
// Output:
13+
// Content length: 132
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<OutputType>Exe</OutputType>
4+
<TargetFramework>net6.0</TargetFramework>
5+
</PropertyGroup>
6+
7+
<ItemGroup>
8+
<Compile Include="Program2.fs" />
9+
<Compile Include="Program.fs" />
10+
</ItemGroup>
11+
</Project>

xml/System/Span`1+Enumerator.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,12 @@ If <xref:System.Span%601.Enumerator.MoveNext%2A> passes the end of the <xref:Sys
5757
The enumerator does not have exclusive access to the <xref:System.Span%601>. In addition, the underlying data on which the span is based can also be modified. Therefore, enumerating through a span is intrinsically not a thread-safe procedure. To guarantee thread safety during enumeration, you must implement your own synchronization. For example, the following code has a race condition. It does not ensure that the span will be enumerated before the `ClearContents` method executes. As a result, the underlying array is cleared during enumeration of the span:
5858
5959
:::code language="csharp" source="~/snippets/csharp/System/Span.Enumerator/Program.cs":::
60+
:::code language="fsharp" source="~/snippets/fsharp/System/Span.Enumerator/Program.fs":::
6061
6162
If you synchronize access to the array before enumerating the span, as the revised version of the `EnumerateSpan` method does in the following example, the `ClearContents` method doesn't modify underlying span data during enumeration. Note that the example locks the underlying array on which the span is based.
6263
6364
:::code language="csharp" source="~/snippets/csharp/System/Span.Enumerator/Program2.cs" id="Snippet1":::
65+
:::code language="fsharp" source="~/snippets/fsharp/System/Span.Enumerator/Program2.fs" id="Snippet1":::
6466
6567
Unlike some other enumerator structures in .NET, the <xref:System.Span%601.Enumerator>:
6668

xml/System/Span`1.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,18 +66,22 @@ For spans that represent immutable or read-only structures, use <xref:System.Rea
6666
A `Span<T>` represents a contiguous region of arbitrary memory. A `Span<T>` instance is often used to hold the elements of an array or a portion of an array. Unlike an array, however, a `Span<T>` instance can point to managed memory, native memory, or memory managed on the stack. The following example creates a `Span<Byte>` from an array:
6767
6868
:::code language="csharp" source="~/snippets/csharp/System/Span/Overview/program.cs" id="Snippet1":::
69+
:::code language="fsharp" source="~/snippets/fsharp/System/Span/Overview/program.fs" id="Snippet1":::
6970
7071
The following example creates a `Span<Byte>` from 100 bytes of native memory:
7172
7273
:::code language="csharp" source="~/snippets/csharp/System/Span/Overview/program.cs" id="Snippet2":::
74+
:::code language="fsharp" source="~/snippets/fsharp/System/Span/Overview/program.fs" id="Snippet2":::
7375
7476
The following example uses the C# [stackalloc](/dotnet/csharp/language-reference/keywords/stackalloc) keyword to allocate 100 bytes of memory on the stack:
7577
7678
:::code language="csharp" source="~/snippets/csharp/System/Span/Overview/program.cs" id="Snippet3":::
79+
:::code language="fsharp" source="~/snippets/fsharp/System/Span/Overview/program.fs" id="Snippet3":::
7780
7881
Because `Span<T>` is an abstraction over an arbitrary block of memory, methods of the `Span<T>` type and methods with `Span<T>` parameters operate on any `Span<T>` object regardless of the kind of memory it encapsulates. For example, each of the separate sections of code that initialize the span and calculate the sum of its elements can be changed into single initialization and calculation methods, as the following example illustrates:
7982
8083
:::code language="csharp" source="~/snippets/csharp/System/Span/Overview/program.cs" id="Snippet4":::
84+
:::code language="fsharp" source="~/snippets/fsharp/System/Span/Overview/program.fs" id="Snippet4":::
8185
8286
## Span\<T> and arrays
8387
@@ -86,6 +90,7 @@ When it wraps an array, `Span<T>` can wrap an entire array, as it did in the exa
8690
The following example creates a slice of the middle five elements of a 10-element integer array. Note that the code doubles the values of each integer in the slice. As the output shows, the changes made by the span are reflected in the values of the array.
8791
8892
:::code language="csharp" source="~/snippets/csharp/System/Span/Slice/Program.cs":::
93+
:::code language="fsharp" source="~/snippets/fsharp/System/Span/Slice/Program.fs":::
8994
9095
## Span\<T> and slices
9196
@@ -98,6 +103,7 @@ The following example creates a slice of the middle five elements of a 10-elemen
98103
This allocation and copy operation can be eliminated by using either `Span<T>` or <xref:System.ReadOnlySpan%601>, as the following example shows:
99104
100105
:::code language="csharp" source="~/snippets/csharp/System/Span/Slice/Program2.cs":::
106+
:::code language="fsharp" source="~/snippets/fsharp/System/Span/Slice/Program2.fs":::
101107
102108
103109
]]></format>
@@ -599,6 +605,7 @@ If pinning a `Span<char>`, the resulting `char*` __is not__ assumed to be null-t
599605
The following example demonstrates creating an integer array, pinning it, and writing each element to the console.
600606
601607
:::code language="csharp" source="~/snippets/csharp/System/ReadOnlySpanT/GetPinnableReference/getpinnablereference1.cs":::
608+
:::code language="fsharp" source="~/snippets/fsharp/System/ReadOnlySpanT/GetPinnableReference/getpinnablereference1.fs":::
602609
603610
]]></format>
604611
</remarks>

0 commit comments

Comments
 (0)