@@ -140,18 +140,20 @@ public static ImmutableList<T> Singleton(T value)
140
140
}
141
141
142
142
/// <summary>
143
- /// Private constructor to disallow any other implementations of this class.
143
+ /// GetHashCode implementation which cannot be overridden
144
+ /// in derived classes in order to preserve the semantics
145
+ /// that ImmutableList instances are equal if and only if
146
+ /// they contain the same items.
144
147
/// </summary>
145
- private ImmutableList ( )
146
- {
147
- }
148
-
149
- public override int GetHashCode ( )
148
+ public sealed override int GetHashCode ( )
150
149
{
151
150
return CollectionUtil . GetHashCodeDeep ( this ) ;
152
151
}
153
152
154
- public override bool Equals ( object o )
153
+ /// <summary>
154
+ /// Equals implementation which cannot be overridden.
155
+ /// </summary>
156
+ public sealed override bool Equals ( object o )
155
157
{
156
158
if ( o == null )
157
159
{
@@ -161,14 +163,35 @@ public override bool Equals(object o)
161
163
{
162
164
return true ;
163
165
}
166
+ if ( GetType ( ) == o . GetType ( ) )
167
+ {
168
+ return SameTypeEquals ( ( ImmutableList < T > ) o ) ;
169
+ }
164
170
var that = o as ImmutableList < T > ;
165
171
if ( null == that )
166
172
{
167
173
return false ;
168
174
}
175
+
176
+ if ( Count != that . Count )
177
+ {
178
+ return false ;
179
+ }
180
+
169
181
return this . SequenceEqual ( that ) ;
170
182
}
171
183
184
+ /// <summary>
185
+ /// Virtual equals implementation which is only called if the list being
186
+ /// compared against is the same type as this. Derived classes may override
187
+ /// this if they have a more efficient way of comparing against other
188
+ /// instances of themselves (e.g. <see cref="ConstantList{T}"/>)
189
+ /// </summary>
190
+ protected virtual bool SameTypeEquals ( ImmutableList < T > list )
191
+ {
192
+ return this . SequenceEqual ( list ) ;
193
+ }
194
+
172
195
public abstract int Count { get ; }
173
196
174
197
void ICollection < T > . Add ( T item )
@@ -204,10 +227,32 @@ IEnumerator IEnumerable.GetEnumerator()
204
227
205
228
public abstract IEnumerator < T > GetEnumerator ( ) ;
206
229
207
- public abstract bool Contains ( T item ) ;
208
- public abstract void CopyTo ( T [ ] array , int arrayIndex ) ;
230
+ public virtual bool Contains ( T item )
231
+ {
232
+ return this . AsEnumerable ( ) . Contains ( item ) ;
233
+ }
234
+ public virtual void CopyTo ( T [ ] array , int arrayIndex )
235
+ {
236
+ foreach ( var item in this )
237
+ {
238
+ array [ arrayIndex ++ ] = item ;
239
+ }
240
+ }
241
+
242
+ public virtual int IndexOf ( T item )
243
+ {
244
+ int index = 0 ;
245
+ foreach ( var v in this )
246
+ {
247
+ if ( Equals ( v , item ) )
248
+ {
249
+ return index ;
250
+ }
251
+ index ++ ;
252
+ }
209
253
210
- public abstract int IndexOf ( T item ) ;
254
+ return - 1 ;
255
+ }
211
256
public abstract T this [ int index ] { get ; }
212
257
213
258
T IList < T > . this [ int index ]
@@ -216,12 +261,12 @@ T IList<T>.this[int index]
216
261
set { throw new InvalidOperationException ( ) ; }
217
262
}
218
263
219
- public abstract ImmutableList < T > ReplaceAt ( int index , T value ) ;
220
-
221
- /// <summary>
222
- /// Replaces the first item in the list that matches the predicate with the given value; throws IndexOutOfRange if no item is replaced.
223
- /// </summary>
224
- public abstract ImmutableList < T > ReplaceElement ( T value , Func < T , bool > predicate ) ;
264
+ public virtual ImmutableList < T > ReplaceAt ( int index , T value )
265
+ {
266
+ var array = this . ToArray ( ) ;
267
+ array [ index ] = value ;
268
+ return ImmutableList . ValueOf ( array ) ;
269
+ }
225
270
226
271
private class Impl : ImmutableList < T >
227
272
{
@@ -271,12 +316,6 @@ public override ImmutableList<T> ReplaceAt(int index, T value)
271
316
newArray [ index ] = value ;
272
317
return new Impl ( newArray ) ;
273
318
}
274
-
275
- public override ImmutableList < T > ReplaceElement ( T value , Func < T , bool > predicate )
276
- {
277
- int index = Array . FindIndex ( _items , t => predicate ( t ) ) ;
278
- return ReplaceAt ( index , value ) ;
279
- }
280
319
}
281
320
282
321
private class SingletonImpl : ImmutableList < T >
@@ -332,14 +371,90 @@ public override ImmutableList<T> ReplaceAt(int index, T value)
332
371
}
333
372
return new SingletonImpl ( value ) ;
334
373
}
374
+ }
375
+ }
335
376
336
- public override ImmutableList < T > ReplaceElement ( T value , Func < T , bool > predicate )
377
+ public class ConstantList < T > : ImmutableList < T >
378
+ {
379
+ private int _count ;
380
+ private T _value ;
381
+ public ConstantList ( int count , T value )
382
+ {
383
+ _count = count ;
384
+ _value = value ;
385
+ }
386
+
387
+ public override IEnumerator < T > GetEnumerator ( )
388
+ {
389
+ return Enumerable . Repeat ( _value , _count ) . GetEnumerator ( ) ;
390
+ }
391
+
392
+ public override int Count
393
+ {
394
+ get { return _count ; }
395
+ }
396
+
397
+ public override T this [ int index ]
398
+ {
399
+ get
337
400
{
338
- if ( ! predicate ( _item ) )
339
- {
340
- throw new IndexOutOfRangeException ( ) ;
341
- }
342
- return ReplaceAt ( 0 , value ) ;
401
+ if ( index < 0 || index >= _count )
402
+ throw new ArgumentOutOfRangeException ( nameof ( index ) ) ;
403
+ return _value ;
404
+ }
405
+ }
406
+
407
+ protected override bool SameTypeEquals ( ImmutableList < T > list )
408
+ {
409
+ var that = ( ConstantList < T > ) list ;
410
+ return Count == list . Count && Equals ( _value , that . _value ) ;
411
+ }
412
+ }
413
+
414
+ /// <summary>
415
+ /// Efficiently stores a list of <see cref="Nullable"/> by using
416
+ /// <see cref="IntegerList.Bits"/>.
417
+ /// </summary>
418
+ public class NullableList < T > : ImmutableList < T ? > where T : struct
419
+ {
420
+ private ImmutableList < int > _hasValueList ;
421
+ private ImmutableList < T > _values ;
422
+
423
+ public NullableList ( IEnumerable < T ? > items )
424
+ {
425
+ var values = new List < T > ( ) ;
426
+ var hasValues = new List < int > ( ) ;
427
+ foreach ( var item in items )
428
+ {
429
+ values . Add ( item . GetValueOrDefault ( ) ) ;
430
+ hasValues . Add ( item . HasValue ? 1 : 0 ) ;
431
+ }
432
+
433
+ _hasValueList = IntegerList . FromIntegers ( hasValues ) ;
434
+ if ( typeof ( T ) == typeof ( int ) )
435
+ {
436
+ _values = ( ImmutableList < T > ) ( object ) IntegerList . FromIntegers ( ( List < int > ) ( object ) values ) ;
437
+ }
438
+ else
439
+ {
440
+ _values = values . ToImmutable ( ) ;
441
+ }
442
+ }
443
+
444
+ public override int Count
445
+ {
446
+ get { return _values . Count ; }
447
+ }
448
+ public override IEnumerator < T ? > GetEnumerator ( )
449
+ {
450
+ return Enumerable . Range ( 0 , Count ) . Select ( i => this [ i ] ) . GetEnumerator ( ) ;
451
+ }
452
+
453
+ public override T ? this [ int index ]
454
+ {
455
+ get
456
+ {
457
+ return _hasValueList [ index ] == 0 ? ( T ? ) null : _values [ index ] ;
343
458
}
344
459
}
345
460
}
0 commit comments