Workaround to remove unnecessary bounds checks when using {ReadOnly}Span.IsEmpty...
[platform/upstream/coreclr.git] / src / System.Private.CoreLib / shared / System / Span.cs
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 using System.ComponentModel;
6 using System.Diagnostics;
7 using System.Runtime.CompilerServices;
8
9 using System.Runtime.Versioning;
10
11 #pragma warning disable 0809  //warning CS0809: Obsolete member 'Span<T>.Equals(object)' overrides non-obsolete member 'object.Equals(object)'
12
13 namespace System
14 {
15     /// <summary>
16     /// Span represents a contiguous region of arbitrary memory. Unlike arrays, it can point to either managed
17     /// or native memory, or to memory allocated on the stack. It is type- and memory-safe.
18     /// </summary>
19     [DebuggerTypeProxy(typeof(SpanDebugView<>))]
20     [DebuggerDisplay("{ToString(),raw}")]
21     public readonly ref partial struct Span<T>
22     {
23         /// <summary>
24         /// The number of items in the span.
25         /// </summary>
26         public int Length
27         {
28             [NonVersionable]
29             get
30             {
31                 return _length;
32             }
33         }
34
35         /// <summary>
36         /// Returns true if Length is 0.
37         /// </summary>
38         public bool IsEmpty
39         {
40             [NonVersionable]
41             get
42             {
43                 // Workaround for https://github.com/dotnet/coreclr/issues/19620
44                 return 0 >= (uint)_length;
45             }
46         }
47
48         /// <summary>
49         /// Returns false if left and right point at the same memory and have the same length.  Note that
50         /// this does *not* check to see if the *contents* are equal.
51         /// </summary>
52         public static bool operator !=(Span<T> left, Span<T> right) => !(left == right);
53
54         /// <summary>
55         /// This method is not supported as spans cannot be boxed. To compare two spans, use operator==.
56         /// <exception cref="System.NotSupportedException">
57         /// Always thrown by this method.
58         /// </exception>
59         /// </summary>
60         [Obsolete("Equals() on Span will always throw an exception. Use == instead.")]
61         [EditorBrowsable(EditorBrowsableState.Never)]
62         public override bool Equals(object obj)
63         {
64             throw new NotSupportedException(SR.NotSupported_CannotCallEqualsOnSpan);
65         }
66
67         /// <summary>
68         /// This method is not supported as spans cannot be boxed.
69         /// <exception cref="System.NotSupportedException">
70         /// Always thrown by this method.
71         /// </exception>
72         /// </summary>
73         [Obsolete("GetHashCode() on Span will always throw an exception.")]
74         [EditorBrowsable(EditorBrowsableState.Never)]
75         public override int GetHashCode()
76         {
77             throw new NotSupportedException(SR.NotSupported_CannotCallGetHashCodeOnSpan);
78         }
79
80         /// <summary>
81         /// Defines an implicit conversion of an array to a <see cref="Span{T}"/>
82         /// </summary>
83         public static implicit operator Span<T>(T[] array) => new Span<T>(array);
84
85         /// <summary>
86         /// Defines an implicit conversion of a <see cref="ArraySegment{T}"/> to a <see cref="Span{T}"/>
87         /// </summary>
88         public static implicit operator Span<T>(ArraySegment<T> segment)
89             => new Span<T>(segment.Array, segment.Offset, segment.Count);
90
91         /// <summary>
92         /// Returns an empty <see cref="Span{T}"/>
93         /// </summary>
94         public static Span<T> Empty => default;
95
96         /// <summary>Gets an enumerator for this span.</summary>
97         public Enumerator GetEnumerator() => new Enumerator(this);
98
99         /// <summary>Enumerates the elements of a <see cref="Span{T}"/>.</summary>
100         public ref struct Enumerator
101         {
102             /// <summary>The span being enumerated.</summary>
103             private readonly Span<T> _span;
104             /// <summary>The next index to yield.</summary>
105             private int _index;
106
107             /// <summary>Initialize the enumerator.</summary>
108             /// <param name="span">The span to enumerate.</param>
109             [MethodImpl(MethodImplOptions.AggressiveInlining)]
110             internal Enumerator(Span<T> span)
111             {
112                 _span = span;
113                 _index = -1;
114             }
115
116             /// <summary>Advances the enumerator to the next element of the span.</summary>
117             [MethodImpl(MethodImplOptions.AggressiveInlining)]
118             public bool MoveNext()
119             {
120                 int index = _index + 1;
121                 if (index < _span.Length)
122                 {
123                     _index = index;
124                     return true;
125                 }
126
127                 return false;
128             }
129
130             /// <summary>Gets the element at the current position of the enumerator.</summary>
131             public ref T Current
132             {
133                 [MethodImpl(MethodImplOptions.AggressiveInlining)]
134                 get => ref _span[_index];
135             }
136         }
137     }
138 }