1- #if ! NETCOREAPP && ! NETSTANDARD2_1
2-
3- using System . Runtime . CompilerServices ;
4- using Microsoft . CodeAnalysis ;
5-
6- namespace System
7- {
8- /// <summary>Represent a type can be used to index a collection either from the start or the end.</summary>
9- /// <remarks>
10- /// Index is used by the C# compiler to support the new index syntax
11- /// <code>
12- /// int[] someArray = new int[5] { 1, 2, 3, 4, 5 } ;
13- /// int lastElement = someArray[^1]; // lastElement = 5
14- /// </code>
15- /// </remarks>
16- #if EMBED_SYSTEM_TYPES
17- [ Embedded ]
18- #endif
19- internal readonly struct Index : IEquatable < Index >
20- {
21- private readonly int _value ;
22-
23- /// <summary>Construct an Index using a value and indicating if the index is from the start or from the end.</summary>
24- /// <param name="value">The index value. it has to be zero or positive number.</param>
25- /// <param name="fromEnd">Indicating if the index is from the start or from the end.</param>
26- /// <remarks>
27- /// If the Index constructed from the end, index value 1 means pointing at the last element and index value 0 means pointing at beyond last element.
28- /// </remarks>
29- [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
30- public Index ( int value , bool fromEnd = false )
31- {
32- if ( value < 0 )
33- {
34- throw new ArgumentOutOfRangeException ( nameof ( value ) , value , "Non-negative number required." ) ;
35- }
36-
37- if ( fromEnd )
38- {
39- _value = ~ value ;
40- }
41- else
42- {
43- _value = value ;
44- }
45- }
46-
47- // The following private constructors mainly created for perf reason to avoid the checks
48- private Index ( int value )
49- {
50- _value = value ;
51- }
52-
53- /// <summary>Create an Index pointing at first element.</summary>
54- public static Index Start => new ( 0 ) ;
55-
56- /// <summary>Create an Index pointing at beyond last element.</summary>
57- public static Index End => new ( ~ 0 ) ;
58-
59- /// <summary>Create an Index from the start at the position indicated by the value.</summary>
60- /// <param name="value">The index value from the start.</param>
61- [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
62- public static Index FromStart ( int value )
63- {
64- if ( value < 0 )
65- {
66- throw new ArgumentOutOfRangeException ( nameof ( value ) , value , "Non-negative number required." ) ;
67- }
68-
69- return new Index ( value ) ;
70- }
71-
72- /// <summary>Create an Index from the end at the position indicated by the value.</summary>
73- /// <param name="value">The index value from the end.</param>
74- [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
75- public static Index FromEnd ( int value )
76- {
77- if ( value < 0 )
78- {
79- throw new ArgumentOutOfRangeException ( nameof ( value ) , value , "Non-negative number required." ) ;
80- }
81-
82- return new Index ( ~ value ) ;
83- }
84-
85- /// <summary>Returns the index value.</summary>
86- public int Value
87- {
88- get
89- {
90- if ( _value < 0 )
91- {
92- return ~ _value ;
93- }
94- else
95- {
96- return _value ;
97- }
98- }
99- }
100-
101- /// <summary>Indicates whether the index is from the start or the end.</summary>
102- public bool IsFromEnd => _value < 0 ;
103-
104- /// <summary>Calculate the offset from the start using the giving collection length.</summary>
105- /// <param name="length">The length of the collection that the Index will be used with. length has to be a positive value</param>
106- /// <remarks>
107- /// For performance reason, we don't validate the input length parameter and the returned offset value against negative values.
108- /// we don't validate either the returned offset is greater than the input length.
109- /// It is expected Index will be used with collections which always have non negative length/count. If the returned offset is negative and
110- /// then used to index a collection will get out of range exception which will be same affect as the validation.
111- /// </remarks>
112- [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
113- public int GetOffset ( int length )
114- {
115- var offset = _value ;
116-
117- if ( IsFromEnd )
118- {
119- // offset = length - (~value)
120- // offset = length + (~(~value) + 1)
121- // offset = length + value + 1
122-
123- offset += length + 1 ;
124- }
125-
126- return offset ;
127- }
128-
129- /// <summary>Indicates whether the current Index object is equal to another object of the same type.</summary>
130- /// <param name="value">An object to compare with this object</param>
131- public override bool Equals ( object ? value ) => value is Index && _value == ( ( Index ) value ) . _value ;
132-
133- /// <summary>Indicates whether the current Index object is equal to another Index object.</summary>
134- /// <param name="other">An object to compare with this object</param>
135- public bool Equals ( Index other ) => _value == other . _value ;
136-
137- /// <summary>Returns the hash code for this instance.</summary>
138- public override int GetHashCode ( ) => _value ;
139-
140- /// <summary>Converts integer number to an Index.</summary>
141- public static implicit operator Index ( int value ) => FromStart ( value ) ;
142-
143- /// <summary>Converts the value of the current Index object to its equivalent string representation.</summary>
144- public override string ToString ( )
145- {
146- if ( IsFromEnd )
147- {
148- return $ "^{ ( ( uint ) Value ) . ToString ( ) } ";
149- }
150-
151- return ( ( uint ) Value ) . ToString ( ) ;
152- }
153- }
154- }
1+ #if ! NETCOREAPP && ! NETSTANDARD2_1 && ! POLYFILL_NO_INDEX
2+
3+ using System . Runtime . CompilerServices ;
4+ using Microsoft . CodeAnalysis ;
5+
6+ namespace System
7+ {
8+ /// <summary>Represent a type can be used to index a collection either from the start or the end.</summary>
9+ /// <remarks>
10+ /// Index is used by the C# compiler to support the new index syntax
11+ /// <code>
12+ /// int[] someArray = new int[5] { 1, 2, 3, 4, 5 } ;
13+ /// int lastElement = someArray[^1]; // lastElement = 5
14+ /// </code>
15+ /// </remarks>
16+ #if EMBED_SYSTEM_TYPES
17+ [ Embedded ]
18+ #endif
19+ internal readonly struct Index : IEquatable < Index >
20+ {
21+ private readonly int _value ;
22+
23+ /// <summary>Construct an Index using a value and indicating if the index is from the start or from the end.</summary>
24+ /// <param name="value">The index value. it has to be zero or positive number.</param>
25+ /// <param name="fromEnd">Indicating if the index is from the start or from the end.</param>
26+ /// <remarks>
27+ /// If the Index constructed from the end, index value 1 means pointing at the last element and index value 0 means pointing at beyond last element.
28+ /// </remarks>
29+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
30+ public Index ( int value , bool fromEnd = false )
31+ {
32+ if ( value < 0 )
33+ {
34+ throw new ArgumentOutOfRangeException ( nameof ( value ) , value , "Non-negative number required." ) ;
35+ }
36+
37+ if ( fromEnd )
38+ {
39+ _value = ~ value ;
40+ }
41+ else
42+ {
43+ _value = value ;
44+ }
45+ }
46+
47+ // The following private constructors mainly created for perf reason to avoid the checks
48+ private Index ( int value )
49+ {
50+ _value = value ;
51+ }
52+
53+ /// <summary>Create an Index pointing at first element.</summary>
54+ public static Index Start => new ( 0 ) ;
55+
56+ /// <summary>Create an Index pointing at beyond last element.</summary>
57+ public static Index End => new ( ~ 0 ) ;
58+
59+ /// <summary>Create an Index from the start at the position indicated by the value.</summary>
60+ /// <param name="value">The index value from the start.</param>
61+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
62+ public static Index FromStart ( int value )
63+ {
64+ if ( value < 0 )
65+ {
66+ throw new ArgumentOutOfRangeException ( nameof ( value ) , value , "Non-negative number required." ) ;
67+ }
68+
69+ return new Index ( value ) ;
70+ }
71+
72+ /// <summary>Create an Index from the end at the position indicated by the value.</summary>
73+ /// <param name="value">The index value from the end.</param>
74+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
75+ public static Index FromEnd ( int value )
76+ {
77+ if ( value < 0 )
78+ {
79+ throw new ArgumentOutOfRangeException ( nameof ( value ) , value , "Non-negative number required." ) ;
80+ }
81+
82+ return new Index ( ~ value ) ;
83+ }
84+
85+ /// <summary>Returns the index value.</summary>
86+ public int Value
87+ {
88+ get
89+ {
90+ if ( _value < 0 )
91+ {
92+ return ~ _value ;
93+ }
94+ else
95+ {
96+ return _value ;
97+ }
98+ }
99+ }
100+
101+ /// <summary>Indicates whether the index is from the start or the end.</summary>
102+ public bool IsFromEnd => _value < 0 ;
103+
104+ /// <summary>Calculate the offset from the start using the giving collection length.</summary>
105+ /// <param name="length">The length of the collection that the Index will be used with. length has to be a positive value</param>
106+ /// <remarks>
107+ /// For performance reason, we don't validate the input length parameter and the returned offset value against negative values.
108+ /// we don't validate either the returned offset is greater than the input length.
109+ /// It is expected Index will be used with collections which always have non negative length/count. If the returned offset is negative and
110+ /// then used to index a collection will get out of range exception which will be same affect as the validation.
111+ /// </remarks>
112+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
113+ public int GetOffset ( int length )
114+ {
115+ var offset = _value ;
116+
117+ if ( IsFromEnd )
118+ {
119+ // offset = length - (~value)
120+ // offset = length + (~(~value) + 1)
121+ // offset = length + value + 1
122+
123+ offset += length + 1 ;
124+ }
125+
126+ return offset ;
127+ }
128+
129+ /// <summary>Indicates whether the current Index object is equal to another object of the same type.</summary>
130+ /// <param name="value">An object to compare with this object</param>
131+ public override bool Equals ( object ? value ) => value is Index && _value == ( ( Index ) value ) . _value ;
132+
133+ /// <summary>Indicates whether the current Index object is equal to another Index object.</summary>
134+ /// <param name="other">An object to compare with this object</param>
135+ public bool Equals ( Index other ) => _value == other . _value ;
136+
137+ /// <summary>Returns the hash code for this instance.</summary>
138+ public override int GetHashCode ( ) => _value ;
139+
140+ /// <summary>Converts integer number to an Index.</summary>
141+ public static implicit operator Index ( int value ) => FromStart ( value ) ;
142+
143+ /// <summary>Converts the value of the current Index object to its equivalent string representation.</summary>
144+ public override string ToString ( )
145+ {
146+ if ( IsFromEnd )
147+ {
148+ return $ "^{ ( ( uint ) Value ) . ToString ( ) } ";
149+ }
150+
151+ return ( ( uint ) Value ) . ToString ( ) ;
152+ }
153+ }
154+ }
155155#endif
0 commit comments