SortedSet: Don't maintain state in the view
[mono.git] / mcs / class / System / System.Collections.Generic / SortedSet.cs
1 //
2 // SortedSet.cs
3 //
4 // Authors:
5 //  Jb Evain  <jbevain@novell.com>
6 //
7 // Copyright (C) 2010 Novell, Inc (http://www.novell.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 using System;
30 using System.Collections;
31 using System.Collections.Generic;
32 using System.Linq;
33 using System.Runtime.Serialization;
34 using System.Runtime.InteropServices;
35 using System.Security;
36 using System.Security.Permissions;
37 using System.Diagnostics;
38
39 // SortedSet is basically implemented as a reduction of SortedDictionary<K, V>
40
41 #if NET_4_0
42
43 namespace System.Collections.Generic {
44
45         [Serializable]
46         [DebuggerDisplay ("Count={Count}")]
47         [DebuggerTypeProxy (typeof (CollectionDebuggerView))]
48         public class SortedSet<T> : ISet<T>, ICollection, ISerializable, IDeserializationCallback
49         {
50                 class Node : RBTree.Node {
51
52                         public T item;
53
54                         public Node (T item)
55                         {
56                                 this.item = item;
57                         }
58
59                         public override void SwapValue (RBTree.Node other)
60                         {
61                                 var o = (Node) other;
62                                 var i = this.item;
63                                 this.item = o.item;
64                                 o.item = i;
65                         }
66                 }
67
68                 class NodeHelper : RBTree.INodeHelper<T> {
69
70                         static NodeHelper Default = new NodeHelper (Comparer<T>.Default);
71
72                         public IComparer<T> comparer;
73
74                         public int Compare (T item, RBTree.Node node)
75                         {
76                                 return comparer.Compare (item, ((Node) node).item);
77                         }
78
79                         public RBTree.Node CreateNode (T item)
80                         {
81                                 return new Node (item);
82                         }
83
84                         NodeHelper (IComparer<T> comparer)
85                         {
86                                 this.comparer = comparer;
87                         }
88
89                         public static NodeHelper GetHelper (IComparer<T> comparer)
90                         {
91                                 if (comparer == null || comparer == Comparer<T>.Default)
92                                         return Default;
93
94                                 return new NodeHelper (comparer);
95                         }
96                 }
97
98                 RBTree tree;
99                 NodeHelper helper;
100                 SerializationInfo si;
101
102                 public SortedSet ()
103                         : this (Comparer<T>.Default)
104                 {
105                 }
106
107                 public SortedSet (IEnumerable<T> collection)
108                         : this (collection, Comparer<T>.Default)
109                 {
110                 }
111
112                 public SortedSet (IEnumerable<T> collection, IComparer<T> comparer)
113                         : this (comparer)
114                 {
115                         if (collection == null)
116                                 throw new ArgumentNullException ("collection");
117
118                         foreach (var item in collection)
119                                 Add (item);
120                 }
121
122                 public SortedSet (IComparer<T> comparer)
123                 {
124                         this.helper = NodeHelper.GetHelper (comparer);
125                         this.tree = new RBTree (this.helper);
126                 }
127
128                 protected SortedSet (SerializationInfo info, StreamingContext context)
129                 {
130                         this.si = info;
131                 }
132
133                 public IComparer<T> Comparer {
134                         get { return helper.comparer; }
135                 }
136
137                 public int Count {
138                         get { return GetCount (); }
139                 }
140
141                 public T Max {
142                         get { return GetMax (); }
143                 }
144
145                 public T Min {
146                         get {  return GetMin (); }
147                 }
148
149                 internal virtual T GetMax ()
150                 {
151                         if (tree.Count == 0)
152                                 return default (T);
153
154                         return GetItem (tree.Count - 1);
155                 }
156
157                 internal virtual T GetMin ()
158                 {
159                         if (tree.Count == 0)
160                                 return default (T);
161
162                         return GetItem (0);
163                 }
164
165                 internal virtual int GetCount ()
166                 {
167                         return tree.Count;
168                 }
169
170                 T GetItem (int index)
171                 {
172                         return ((Node) tree [index]).item;
173                 }
174
175                 public bool Add (T item)
176                 {
177                         return TryAdd (item);
178                 }
179
180                 internal virtual bool TryAdd (T item)
181                 {
182                         var node = new Node (item);
183                         return tree.Intern (item, node) == node;
184                 }
185
186                 public virtual void Clear ()
187                 {
188                         tree.Clear ();
189                 }
190
191                 public virtual bool Contains (T item)
192                 {
193                         return tree.Lookup (item) != null;
194                 }
195
196                 public void CopyTo (T [] array)
197                 {
198                         CopyTo (array, 0, Count);
199                 }
200
201                 public void CopyTo (T [] array, int index)
202                 {
203                         CopyTo (array, index, Count);
204                 }
205
206                 public void CopyTo (T [] array, int index, int count)
207                 {
208                         if (array == null)
209                                 throw new ArgumentNullException ("array");
210                         if (index < 0)
211                                 throw new ArgumentOutOfRangeException ("index");
212                         if (index > array.Length)
213                                 throw new ArgumentException ("index larger than largest valid index of array");
214                         if (array.Length - index < count)
215                                 throw new ArgumentException ("destination array cannot hold the requested elements");
216
217                         foreach (Node node in tree) {
218                                 if (count-- == 0)
219                                         break;
220
221                                 array [index++] = node.item;
222                         }
223                 }
224
225                 public bool Remove (T item)
226                 {
227                         return TryRemove (item);
228                 }
229
230                 internal virtual bool TryRemove (T item)
231                 {
232                         return tree.Remove (item) != null;
233                 }
234
235                 public int RemoveWhere (Predicate<T> match)
236                 {
237                         var array = ToArray ();
238
239                         int count = 0;
240                         foreach (var item in array) {
241                                 if (!match (item))
242                                         continue;
243
244                                 Remove (item);
245                                 count++;
246                         }
247
248                         return count;
249                 }
250
251                 public IEnumerable<T> Reverse ()
252                 {
253                         for (int i = tree.Count - 1; i >= 0; i--)
254                                 yield return GetItem (i);
255                 }
256
257                 T [] ToArray ()
258                 {
259                         var array = new T [this.Count];
260                         CopyTo (array);
261                         return array;
262                 }
263
264                 public Enumerator GetEnumerator ()
265                 {
266                         return TryGetEnumerator ();
267                 }
268
269                 internal virtual Enumerator TryGetEnumerator ()
270                 {
271                         return new Enumerator (this);
272                 }
273
274                 IEnumerator<T> IEnumerable<T>.GetEnumerator ()
275                 {
276                         return GetEnumerator ();
277                 }
278
279                 IEnumerator IEnumerable.GetEnumerator ()
280                 {
281                         return GetEnumerator ();
282                 }
283
284                 public static IEqualityComparer<SortedSet<T>> CreateSetComparer ()
285                 {
286                         return CreateSetComparer (EqualityComparer<T>.Default);
287                 }
288
289                 [MonoTODO]
290                 public static IEqualityComparer<SortedSet<T>> CreateSetComparer (IEqualityComparer<T> memberEqualityComparer)
291                 {
292                         throw new NotImplementedException ();
293                 }
294
295                 [MonoTODO]
296                 protected virtual void GetObjectData (SerializationInfo info, StreamingContext context)
297                 {
298                         throw new NotImplementedException ();
299                 }
300
301                 void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context)
302                 {
303                         GetObjectData (info, context);
304                 }
305
306                 [MonoTODO]
307                 protected virtual void OnDeserialization (object sender)
308                 {
309                         if (si == null)
310                                 return;
311
312                         throw new NotImplementedException ();
313                 }
314
315                 void IDeserializationCallback.OnDeserialization (object sender)
316                 {
317                         OnDeserialization (sender);
318                 }
319
320                 [MonoLimitation ("Isn't O(n) when other is SortedSet<T>")]
321                 public void ExceptWith (IEnumerable<T> other)
322                 {
323                         CheckArgumentNotNull (other, "other");
324                         foreach (T item in other)
325                                 Remove (item);
326                 }
327
328                 public virtual SortedSet<T> GetViewBetween (T lowerValue, T upperValue)
329                 {
330                         if (Comparer.Compare (lowerValue, upperValue) > 0)
331                                 throw new ArgumentException ("The lowerValue is bigger than upperValue");
332
333                         return new SortedSubSet (this, lowerValue, upperValue);
334                 }
335
336                 [MonoLimitation ("Isn't O(n) when other is SortedSet<T>")]
337                 public virtual void IntersectWith (IEnumerable<T> other)
338                 {
339                         CheckArgumentNotNull (other, "other");
340
341                         RBTree newtree = new RBTree (helper);
342                         foreach (T item in other) {
343                                 var node = tree.Remove (item);
344                                 if (node != null)
345                                         newtree.Intern (item, node);
346                         }
347                         tree = newtree;
348                 }
349
350                 public bool IsProperSubsetOf (IEnumerable<T> other)
351                 {
352                         CheckArgumentNotNull (other, "other");
353
354                         if (Count == 0) {
355                                 foreach (T item in other)
356                                         return true; // this idiom means: if 'other' is non-empty, return true
357                                 return false;
358                         }
359
360                         return is_subset_of (other, true);
361                 }
362
363                 public bool IsProperSupersetOf (IEnumerable<T> other)
364                 {
365                         CheckArgumentNotNull (other, "other");
366
367                         if (Count == 0)
368                                 return false;
369
370                         return is_superset_of (other, true);
371                 }
372
373                 public bool IsSubsetOf (IEnumerable<T> other)
374                 {
375                         CheckArgumentNotNull (other, "other");
376
377                         if (Count == 0)
378                                 return true;
379
380                         return is_subset_of (other, false);
381                 }
382
383                 public bool IsSupersetOf (IEnumerable<T> other)
384                 {
385                         CheckArgumentNotNull (other, "other");
386
387                         if (Count == 0) {
388                                 foreach (T item in other)
389                                         return false; // this idiom means: if 'other' is non-empty, return false
390                                 return true;
391                         }
392
393                         return is_superset_of (other, false);
394                 }
395
396                 // Precondition: Count != 0, other != null
397                 bool is_subset_of (IEnumerable<T> other, bool proper)
398                 {
399                         SortedSet<T> that = nodups (other);
400
401                         if (Count > that.Count)
402                                 return false;
403                         // Count != 0 && Count <= that.Count => that.Count != 0
404                         if (proper && Count == that.Count)
405                                 return false;
406                         return that.covers (this);
407                 }
408
409                 // Precondition: Count != 0, other != null
410                 bool is_superset_of (IEnumerable<T> other, bool proper)
411                 {
412                         SortedSet<T> that = nodups (other);
413
414                         if (that.Count == 0)
415                                 return true;
416                         if (Count < that.Count)
417                                 return false;
418                         if (proper && Count == that.Count)
419                                 return false;
420                         return this.covers (that);
421                 }
422
423                 public bool Overlaps (IEnumerable<T> other)
424                 {
425                         CheckArgumentNotNull (other, "other");
426
427                         if (Count == 0)
428                                 return false;
429
430                         // Don't use 'nodups' here.  Only optimize the SortedSet<T> case
431                         SortedSet<T> that = other as SortedSet<T>;
432                         if (that != null && that.Comparer != Comparer)
433                                 that = null;
434
435                         if (that != null)
436                                 return that.Count != 0 && overlaps (that);
437
438                         foreach (T item in other)
439                                 if (Contains (item))
440                                         return true;
441                         return false;
442                 }
443
444                 public bool SetEquals (IEnumerable<T> other)
445                 {
446                         CheckArgumentNotNull (other, "other");
447
448                         if (Count == 0) {
449                                 foreach (T item in other)
450                                         return false;
451                                 return true;
452                         }
453
454                         SortedSet<T> that = nodups (other);
455
456                         if (Count != that.Count)
457                                 return false;
458
459                         using (var t = that.GetEnumerator ()) {
460                                 foreach (T item in this) {
461                                         if (!t.MoveNext ())
462                                                 throw new SystemException ("count wrong somewhere: this longer than that");
463                                         if (Comparer.Compare (item, t.Current) != 0)
464                                                 return false;
465                                 }
466                                 if (t.MoveNext ())
467                                         throw new SystemException ("count wrong somewhere: this shorter than that");
468                                 return true;
469                         }
470                 }
471
472                 SortedSet<T> nodups (IEnumerable<T> other)
473                 {
474                         SortedSet<T> that = other as SortedSet<T>;
475                         if (that != null && that.Comparer == Comparer)
476                                 return that;
477                         return new SortedSet<T> (other, Comparer);
478                 }
479
480                 bool covers (SortedSet<T> that)
481                 {
482                         using (var t = that.GetEnumerator ()) {
483                                 if (!t.MoveNext ())
484                                         return true;
485                                 foreach (T item in this) {
486                                         int cmp = Comparer.Compare (item, t.Current);
487                                         if (cmp > 0)
488                                                 return false;
489                                         if (cmp == 0 && !t.MoveNext ())
490                                                 return true;
491                                 }
492                                 return false;
493                         }
494                 }
495
496                 bool overlaps (SortedSet<T> that)
497                 {
498                         using (var t = that.GetEnumerator ()) {
499                                 if (!t.MoveNext ())
500                                         return false;
501                                 foreach (T item in this) {
502                                         int cmp;
503                                         while ((cmp = Comparer.Compare (item, t.Current)) > 0) {
504                                                 if (!t.MoveNext ())
505                                                         return false;
506                                         }
507                                         if (cmp == 0)
508                                                 return true;
509                                 }
510                                 return false;
511                         }
512                 }
513
514                 [MonoLimitation ("Isn't O(n) when other is SortedSet<T>")]
515                 public void SymmetricExceptWith (IEnumerable<T> other)
516                 {
517                         SortedSet<T> that_minus_this = new SortedSet<T> (Comparer);
518
519                         // compute this - that and that - this in parallel
520                         foreach (T item in nodups (other))
521                                 if (!Remove (item))
522                                         that_minus_this.Add (item);
523
524                         UnionWith (that_minus_this);
525                 }
526
527                 [MonoLimitation ("Isn't O(n) when other is SortedSet<T>")]
528                 public void UnionWith (IEnumerable<T> other)
529                 {
530                         CheckArgumentNotNull (other, "other");
531
532                         foreach (T item in other)
533                                 Add (item);
534                 }
535
536                 static void CheckArgumentNotNull (object arg, string name)
537                 {
538                         if (arg == null)
539                                 throw new ArgumentNullException (name);
540                 }
541
542                 void ICollection<T>.Add (T item)
543                 {
544                         Add (item);
545                 }
546
547                 void ICollection<T>.CopyTo (T [] array, int index)
548                 {
549                         CopyTo (array, index, Count);
550                 }
551
552                 bool ICollection<T>.IsReadOnly {
553                         get { return false; }
554                 }
555
556                 void ICollection.CopyTo (Array array, int index)
557                 {
558                         if (Count == 0)
559                                 return;
560                         if (array == null)
561                                 throw new ArgumentNullException ("array");
562                         if (index < 0 || array.Length <= index)
563                                 throw new ArgumentOutOfRangeException ("index");
564                         if (array.Length - index < Count)
565                                 throw new ArgumentException ();
566
567                         foreach (Node node in tree)
568                                 array.SetValue (node.item, index++);
569                 }
570
571                 bool ICollection.IsSynchronized {
572                         get { return false; }
573                 }
574
575                 // TODO:Is this correct? If this is wrong,please fix.
576                 object ICollection.SyncRoot {
577                         get { return this; }
578                 }
579
580                 [Serializable]
581                 public struct Enumerator : IEnumerator<T>, IDisposable {
582
583                         RBTree.NodeEnumerator host;
584
585                         IComparer<T> comparer;
586
587                         T current;
588                         T upper;
589
590                         internal Enumerator (SortedSet<T> set)
591                                 : this ()
592                         {
593                                 host = set.tree.GetEnumerator ();
594                         }
595
596                         internal Enumerator (SortedSet<T> set, T lower, T upper)
597                                 : this ()
598                         {
599                                 host = set.tree.GetSuffixEnumerator (lower);
600                                 comparer = set.Comparer;
601                                 this.upper = upper;
602                         }
603
604                         public T Current {
605                                 get { return current; }
606                         }
607
608                         object IEnumerator.Current {
609                                 get {
610                                         host.check_current ();
611                                         return ((Node) host.Current).item;
612                                 }
613                         }
614
615                         public bool MoveNext ()
616                         {
617                                 if (!host.MoveNext ())
618                                         return false;
619
620                                 current = ((Node) host.Current).item;
621                                 return comparer == null || comparer.Compare (upper, current) >= 0;
622                         }
623
624                         public void Dispose ()
625                         {
626                                 host.Dispose ();
627                         }
628
629                         void IEnumerator.Reset ()
630                         {
631                                 host.Reset ();
632                         }
633                 }
634
635                 [Serializable]
636                 sealed class SortedSubSet : SortedSet<T>, IEnumerable<T>, IEnumerable {
637
638                         SortedSet<T> set;
639                         T lower;
640                         T upper;
641
642                         public SortedSubSet (SortedSet<T> set, T lower, T upper)
643                                 : base (set.Comparer)
644                         {
645                                 this.set = set;
646                                 this.lower = lower;
647                                 this.upper = upper;
648
649                         }
650
651                         internal override T GetMin ()
652                         {
653                                 RBTree.Node lb = null, ub = null;
654                                 set.tree.Bound (lower, ref lb, ref ub);
655
656                                 if (ub == null || set.helper.Compare (upper, ub) < 0)
657                                         return default (T);
658
659                                 return ((Node) ub).item;
660                         }
661
662                         internal override T GetMax ()
663                         {
664                                 RBTree.Node lb = null, ub = null;
665                                 set.tree.Bound (upper, ref lb, ref ub);
666
667                                 if (lb == null || set.helper.Compare (lower, lb) > 0)
668                                         return default (T);
669
670                                 return ((Node) lb).item;
671                         }
672
673                         internal override int GetCount ()
674                         {
675                                 int count = 0;
676                                 using (var e = set.tree.GetSuffixEnumerator (lower)) {
677                                         while (e.MoveNext () && set.helper.Compare (upper, e.Current) >= 0)
678                                                 ++count;
679                                 }
680                                 return count;
681                         }
682
683                         internal override bool TryAdd (T item)
684                         {
685                                 if (!InRange (item))
686                                         throw new ArgumentOutOfRangeException ("item");
687
688                                 return set.TryAdd (item);
689                         }
690
691                         internal override bool TryRemove (T item)
692                         {
693                                 if (!InRange (item))
694                                         return false;
695
696                                 return set.TryRemove (item);
697                         }
698
699                         public override bool Contains (T item)
700                         {
701                                 if (!InRange (item))
702                                         return false;
703
704                                 return set.Contains (item);
705                         }
706
707                         public override void Clear ()
708                         {
709                                 set.RemoveWhere (InRange);
710                         }
711
712                         bool InRange (T item)
713                         {
714                                 return Comparer.Compare (item, lower) >= 0
715                                         && Comparer.Compare (item, upper) <= 0;
716                         }
717
718                         public override SortedSet<T> GetViewBetween (T lowerValue, T upperValue)
719                         {
720                                 if (Comparer.Compare (lowerValue, upperValue) > 0)
721                                         throw new ArgumentException ("The lowerValue is bigger than upperValue");
722                                 if (!InRange (lowerValue))
723                                         throw new ArgumentOutOfRangeException ("lowerValue");
724                                 if (!InRange (upperValue))
725                                         throw new ArgumentOutOfRangeException ("upperValue");
726
727                                 return new SortedSubSet (set, lowerValue, upperValue);
728                         }
729
730                         internal override Enumerator TryGetEnumerator ()
731                         {
732                                 return new Enumerator (set, lower, upper);
733                         }
734
735                         public override void IntersectWith (IEnumerable<T> other)
736                         {
737                                 CheckArgumentNotNull (other, "other");
738
739                                 var slice = new SortedSet<T> (this);
740                                 slice.IntersectWith (other);
741
742                                 Clear ();
743                                 set.UnionWith (slice);
744                         }
745                 }
746         }
747 }
748
749 #endif