Skip to content

Documentation for Span<T> #194

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
May 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 52 additions & 8 deletions xml/System/Span`1+Enumerator.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,30 @@
</Attribute>
</Attributes>
<Docs>
<summary>To be added.</summary>
<remarks>To be added.</remarks>
<summary>Provides an enumerator for the elements of a <see cref="T:System.Span`1" />.</summary>
<remarks>
<format type="text/markdown"><![CDATA[

The C# [foreach](~/docs/csharp/language-reference/keywords/foreach-in.md) of the C# language and the [For Each...Next](~/docs/visual-basic/language-reference/statements/for-each-next-statement.md) construct in Visual Basic hides the complexity of enumerators. Instead of directly manipulating the enumerator, using `foreach` or `For Each...Next` is recommended.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be worth mentioning these two points:

Span<T>.Enumerator does not implement IEnumarator<T>.
Span<T>.Enumerator does not have a Reset() method.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@BillWagner, thanks. These are definitely worth mentioning.


Enumerators can be used to read the data in the <xref:System.Span%601>, but they cannot be used to modify it.

Initially, the enumerator is positioned before the first element in the <xref:System.Span%601>. At this position, <xref:System.Span%601.Enumerator.Current> is undefined, so you must call <xref:System.Span%601.Enumerator.MoveNext%2A> to advance the enumerator to the first item in the <xref:System.Span%601> before reading the value of <xref:System.Span%601.Enumerator.Current>.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this position, Current throws an exception (it isn't undefined exactly).


<xref:System.Span%601.Enumerator.Current> returns the same object until <xref:System.Span%601.Enumerator.MoveNext%2A> is called. <xref:System.Span%601.Enumerator.MoveNext%2A> sets <xref:System.Span%601.Enumerator.Current> to the next item in the <xref:System.Span%601>.

If <xref:System.Span%601.Enumerator.MoveNext%2A> passes the end of the <xref:System.Span%601>, the enumerator is positioned after the last item in the <xref:System.Span%601>, and <xref:System.Span%601.Enumerator.MoveNext%2A> returns `false`. When the enumerator is at this position, subsequent calls to <xref:System.Span%601.Enumerator.MoveNext%2A> also return `false`. If the call to <xref:System.Span%601.Enumerator.MoveNext%2A> returns `false`, <xref:System.Span%601.Enumerator.Current> is undefined. You cannot set <xref:System.Span%601.Enumerator.Current> to the first item in the <xref:System.Span%601> again; you must create a new enumerator instance instead.

The enumerator does not have exclusive access to the <xref:System.Span%601>; therefore, enumerating through a span is intrinsically not a thread-safe procedure. To guarantee thread safety during enumeration, you can lock the span during the entire enumeration. To allow the span to be accessed by multiple threads for reading and writing, you must implement your own synchronization.
Copy link
Contributor

@ahsonkhan ahsonkhan May 23, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To guarantee thread safety during enumeration, you can lock the span during the entire enumeration.

@stephentoub, is this true? Couldn't the underlying array still be modified by another thread, or is the implication that the user needs some synchronization mechanism during enumeration and modification of the array? Also, how do we "lock" the span (it isn't a reference type).

The following snippet has a race. To resolve it, we have to use a locking mechanism around both critical sections.
Output:
62
23
0
0
0

static void Main(string[] args)
{
    new Random(42).NextBytes(_array);
    Span<byte> span = _array;

    Thread thread = new Thread(delegate ()
    {
        ClearContents();
    });

    thread.Start();

    EnumerateSpan(span);
}

private static readonly byte[] _array = new byte[5];

public static void ClearContents()
{
    Thread.Sleep(20);
    lock (_array)
    {
        Array.Clear(_array, 0, _array.Length);
    }
}

public static void EnumerateSpan(Span<byte> span)
{
    //lock (_array)
    //{
        foreach (byte element in span)
        {
            Console.WriteLine(element);
            Thread.Sleep(10);
        }
    //}
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First and foremost, there's no way to "lock the span".

Presumably this was really just meant to say that you can use your own synchronization to enforce mutual exclusion.


Unlike some other enumerator structures in .NET, <xref:System.Span%601.Enumerator>:

- Does not implement the <xref:System.Collections.IEnumerator> or <xref:System.Collections.Generic.IEnumerator%601> interface.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth mentioning that it's a ref struct and thus can't implement interfaces.


- Does not include a `Reset` method, which sets the enumerator to its initial position before the first element in the span.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most enumerators provide Reset as it's part of the interface but throw or otherwise don't actually implement it.


]]></format>
</remarks>
</Docs>
<Members>
<Member MemberName="Current">
Expand All @@ -40,9 +62,23 @@
<ReturnType>T@</ReturnType>
</ReturnValue>
<Docs>
<summary>To be added.</summary>
<value>To be added.</value>
<remarks>To be added.</remarks>
<summary>Gets the item at the current position of the enumerator.</summary>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe Gets a reference to the item rather than Gets the item?

<value>The element in the <see cref="T:System.Span`1" /> at the current position of the enumerator.</value>
<remarks>
<format type="text/markdown"><![CDATA[

`Current` throws an <xref:System.IndexOutOfRangeException> under either of the following conditions:

- Immediately after the enumertor is created, the enumerator is positioned before the first element in the span. <xref:System.Span%601.Enumerator.MoveNext%2A> must be called to advance the enumerator to the first element of the span before reading the value of `Current`.

- The last call to <xref:System.Span%601.Enumerator.MoveNext%2A> returned `false`, which indicates the end of the span.

`Current` returns the same object until <xref:System.Span%601.Enumerator.MoveNext%2A> is called. <xref:System.Span%601.Enumerator.MoveNext%2A> sets `Current` to the next item in the span.

]]></format>
</remarks>
<exception cref="T:System.IndexOutOfRangeException">
The enumerator is positioned either before the first item or after the last item in the <see cref="System.Span`1" />.</exception>
</Docs>
</Member>
<Member MemberName="MoveNext">
Expand All @@ -61,9 +97,17 @@
</ReturnValue>
<Parameters />
<Docs>
<summary>To be added.</summary>
<returns>To be added.</returns>
<remarks>To be added.</remarks>
<summary>Advances the enumerator to the next item of the <see cref="System.Span`1" />.</summary>
<returns>`true` if the enumerator successfully advanced to the next item; `false` if the enumerator has passed the end of the span.</returns>
<remarks>
<format type="text/markdown"><![CDATA[

After an enumerator is created,it is positioned before the first element in the span, and the first call to `MoveNext` advances the enumerator to the first item in the span.

If `MoveNext` passes the end of the span, the enumerator is positioned after the last item in the span, and `MoveNext` returns `false`. When the enumerator is at this position, subsequent calls to `MoveNext` also return `false`.

]]></format>
</remarks>
</Docs>
</Member>
</Members>
Expand Down
Loading