18
18
using System . Collections . Generic ;
19
19
using System . Diagnostics . Contracts ;
20
20
using System . Runtime . CompilerServices ;
21
+ using System . Threading ;
21
22
22
23
namespace Microsoft . Python . Core . Collections {
23
24
/// <summary>
@@ -28,10 +29,13 @@ namespace Microsoft.Python.Core.Collections {
28
29
/// <typeparam name="T"></typeparam>
29
30
public struct ImmutableArray < T > : IReadOnlyList < T > , IEquatable < ImmutableArray < T > > {
30
31
private readonly T [ ] _items ;
32
+ private readonly Ref _ref ;
33
+ private readonly int _count ;
31
34
32
35
private ImmutableArray ( T [ ] items , int count ) {
33
36
_items = items ;
34
- Count = count ;
37
+ _ref = new Ref ( ) ;
38
+ _count = count ;
35
39
}
36
40
37
41
public static ImmutableArray < T > Empty { get ; } = new ImmutableArray < T > ( Array . Empty < T > ( ) , 0 ) ;
@@ -67,26 +71,26 @@ public static ImmutableArray<T> Create<TKey>(Dictionary<TKey, T>.ValueCollection
67
71
}
68
72
69
73
public T this [ int index ] => _items [ index ] ;
70
- public int Count { get ; } // Length of the ImmutableArray.
74
+ public int Count => _count ; // Length of the ImmutableArray.
71
75
72
76
[ Pure ]
73
77
public ImmutableArray < T > Add ( T item ) {
74
- var newCount = Count + 1 ;
78
+ var newCount = _count + 1 ;
75
79
var newItems = _items ;
76
80
77
- if ( newCount > _items . Length ) {
81
+ if ( newCount > _items . Length || Interlocked . CompareExchange ( ref _ref . Count , newCount , _count ) != _count ) {
78
82
var capacity = GetCapacity ( newCount ) ;
79
83
newItems = new T [ capacity ] ;
80
- Array . Copy ( _items , 0 , newItems , 0 , Count ) ;
84
+ Array . Copy ( _items , 0 , newItems , 0 , _count ) ;
81
85
}
82
86
83
- newItems [ Count ] = item ;
87
+ newItems [ _count ] = item ;
84
88
return new ImmutableArray < T > ( newItems , newCount ) ;
85
89
}
86
90
87
91
[ Pure ]
88
92
public ImmutableArray < T > AddRange ( in ImmutableArray < T > items )
89
- => AddRange ( items . _items , items . Count ) ;
93
+ => AddRange ( items . _items , items . _count ) ;
90
94
91
95
[ Pure ]
92
96
public ImmutableArray < T > AddRange ( in T [ ] items )
@@ -98,16 +102,16 @@ private ImmutableArray<T> AddRange(in T[] items, int itemsCount) {
98
102
return this ;
99
103
}
100
104
101
- var newCount = Count + itemsCount ;
105
+ var newCount = _count + itemsCount ;
102
106
var newItems = _items ;
103
107
104
- if ( newCount > _items . Length ) {
108
+ if ( newCount > _items . Length || Interlocked . CompareExchange ( ref _ref . Count , newCount , _count ) != _count ) {
105
109
var capacity = GetCapacity ( newCount ) ;
106
110
newItems = new T [ capacity ] ;
107
- Array . Copy ( _items , 0 , newItems , 0 , Count ) ;
111
+ Array . Copy ( _items , 0 , newItems , 0 , _count ) ;
108
112
}
109
113
110
- Array . Copy ( items , 0 , newItems , Count , itemsCount ) ;
114
+ Array . Copy ( items , 0 , newItems , _count , itemsCount ) ;
111
115
return new ImmutableArray < T > ( newItems , newCount ) ;
112
116
}
113
117
@@ -119,7 +123,7 @@ public ImmutableArray<T> Remove(T value) {
119
123
120
124
[ Pure ]
121
125
public ImmutableArray < T > RemoveAt ( int index ) {
122
- var newCount = Count - 1 ;
126
+ var newCount = _count - 1 ;
123
127
124
128
var capacity = GetCapacity ( newCount ) ;
125
129
var newArray = new T [ capacity ] ;
@@ -137,15 +141,15 @@ public ImmutableArray<T> RemoveAt(int index) {
137
141
138
142
[ Pure ]
139
143
public ImmutableArray < T > InsertAt ( int index , T value ) {
140
- if ( index > Count ) {
144
+ if ( index > _count ) {
141
145
throw new IndexOutOfRangeException ( ) ;
142
146
}
143
147
144
- if ( index == Count ) {
148
+ if ( index == _count ) {
145
149
return Add ( value ) ;
146
150
}
147
151
148
- var newCount = Count + 1 ;
152
+ var newCount = _count + 1 ;
149
153
var capacity = GetCapacity ( newCount ) ;
150
154
var newArray = new T [ capacity ] ;
151
155
@@ -154,7 +158,7 @@ public ImmutableArray<T> InsertAt(int index, T value) {
154
158
}
155
159
156
160
newArray [ index ] = value ;
157
- Array . Copy ( _items , index , newArray , index + 1 , Count - index ) ;
161
+ Array . Copy ( _items , index , newArray , index + 1 , _count - index ) ;
158
162
159
163
return new ImmutableArray < T > ( newArray , newCount ) ;
160
164
}
@@ -169,44 +173,45 @@ public ImmutableArray<T> ReplaceAt(int startIndex, int length, T value) {
169
173
return ReplaceAt ( startIndex , value ) ;
170
174
}
171
175
172
- var newCount = Math . Max ( Count - length + 1 , startIndex + 1 ) ;
176
+ var newCount = Math . Max ( _count - length + 1 , startIndex + 1 ) ;
173
177
var capacity = GetCapacity ( newCount ) ;
174
178
var newArray = new T [ capacity ] ;
175
179
176
180
if ( startIndex > 0 ) {
177
181
Array . Copy ( _items , newArray , startIndex ) ;
178
182
}
179
183
180
- newArray [ startIndex + 1 ] = value ;
184
+ newArray [ startIndex ] = value ;
181
185
182
- if ( startIndex + 2 < newCount ) {
183
- Array . Copy ( _items , startIndex + length + 1 , newArray , startIndex + 1 , newCount - startIndex - 2 ) ;
186
+ var afterChangeIndex = startIndex + length ;
187
+ if ( afterChangeIndex < _count ) {
188
+ Array . Copy ( _items , afterChangeIndex , newArray , startIndex + 1 , _count - afterChangeIndex ) ;
184
189
}
185
190
186
191
return new ImmutableArray < T > ( newArray , newCount ) ;
187
192
}
188
193
189
194
[ Pure ]
190
195
public ImmutableArray < T > ReplaceAt ( int index , T value ) {
191
- var capacity = GetCapacity ( Count ) ;
196
+ var capacity = GetCapacity ( _count ) ;
192
197
var newArray = new T [ capacity ] ;
193
- Array . Copy ( _items , newArray , Count ) ;
198
+ Array . Copy ( _items , newArray , _count ) ;
194
199
newArray [ index ] = value ;
195
- return new ImmutableArray < T > ( newArray , Count ) ;
200
+ return new ImmutableArray < T > ( newArray , _count ) ;
196
201
}
197
202
198
203
[ Pure ]
199
204
public ImmutableArray < T > Where ( Func < T , bool > predicate ) {
200
205
var count = 0 ;
201
- for ( var i = 0 ; i < Count ; i ++ ) {
206
+ for ( var i = 0 ; i < _count ; i ++ ) {
202
207
if ( predicate ( _items [ i ] ) ) {
203
208
count ++ ;
204
209
}
205
210
}
206
211
207
212
var index = 0 ;
208
213
var items = new T [ count ] ;
209
- for ( var i = 0 ; i < Count ; i ++ ) {
214
+ for ( var i = 0 ; i < _count ; i ++ ) {
210
215
if ( predicate ( _items [ i ] ) ) {
211
216
items [ index ] = _items [ i ] ;
212
217
index ++ ;
@@ -218,15 +223,15 @@ public ImmutableArray<T> Where(Func<T, bool> predicate) {
218
223
219
224
[ Pure ]
220
225
public ImmutableArray < TResult > Select < TResult > ( Func < T , TResult > selector ) {
221
- var items = new TResult [ Count ] ;
222
- for ( var i = 0 ; i < Count ; i ++ ) {
226
+ var items = new TResult [ _count ] ;
227
+ for ( var i = 0 ; i < _count ; i ++ ) {
223
228
items [ i ] = selector ( _items [ i ] ) ;
224
229
}
225
230
return new ImmutableArray < TResult > ( items , items . Length ) ;
226
231
}
227
232
228
233
[ Pure ]
229
- public int IndexOf ( T value ) => Array . IndexOf ( _items , value , 0 , Count ) ;
234
+ public int IndexOf ( T value ) => Array . IndexOf ( _items , value , 0 , _count ) ;
230
235
231
236
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
232
237
private int GetCapacity ( int length ) {
@@ -248,14 +253,14 @@ private int GetCapacity(int length) {
248
253
}
249
254
250
255
public bool Equals ( ImmutableArray < T > other )
251
- => Equals ( _items , other . _items ) && Count == other . Count ;
256
+ => Equals ( _items , other . _items ) && _count == other . _count ;
252
257
253
258
public override bool Equals ( object obj ) => obj is ImmutableArray < T > other && Equals ( other ) ;
254
259
255
260
public override int GetHashCode ( ) {
256
261
unchecked {
257
262
var hashCode = ( _items != null ? _items . GetHashCode ( ) : 0 ) ;
258
- hashCode = ( hashCode * 397 ) ^ Count ;
263
+ hashCode = ( hashCode * 397 ) ^ _count ;
259
264
return hashCode ;
260
265
}
261
266
}
@@ -292,13 +297,13 @@ public void Dispose() { }
292
297
public bool MoveNext ( ) {
293
298
var localList = _owner ;
294
299
295
- if ( _index < localList . Count ) {
300
+ if ( _index < localList . _count ) {
296
301
Current = localList . _items [ _index ] ;
297
302
_index ++ ;
298
303
return true ;
299
304
}
300
305
301
- _index = _owner . Count + 1 ;
306
+ _index = _owner . _count + 1 ;
302
307
Current = default ;
303
308
return false ;
304
309
}
@@ -312,5 +317,9 @@ void IEnumerator.Reset() {
312
317
Current = default ;
313
318
}
314
319
}
320
+
321
+ private class Ref {
322
+ public int Count ;
323
+ }
315
324
}
316
325
}
0 commit comments