Merge pull request #439 from mono-soc-2012/garyb/iconfix
[mono.git] / mcs / class / System.Core / System.Collections.Generic / HashSet.cs
index 5a382c1df630658ce1656b1db4c5242088e7a198..a417557d035886e547a32e820076df09524c0111 100644 (file)
@@ -44,7 +44,7 @@ namespace System.Collections.Generic {
        [DebuggerDisplay ("Count={Count}")]
        [DebuggerTypeProxy (typeof (CollectionDebuggerView<,>))]
        public class HashSet<T> : ICollection<T>, ISerializable, IDeserializationCallback
-#if NET_4_0
+#if NET_4_0 || MOONLIGHT || MOBILE
                                                        , ISet<T>
 #endif
        {
@@ -176,26 +176,26 @@ namespace System.Collections.Generic {
                {
                        CopyTo (array, 0, count);
                }
-
-               public void CopyTo (T [] array, int index)
+               
+               public void CopyTo (T [] array, int arrayIndex)
                {
-                       CopyTo (array, index, count);
+                       CopyTo (array, arrayIndex, count);
                }
 
-               public void CopyTo (T [] array, int index, int count)
+               public void CopyTo (T [] array, int arrayIndex, int count)
                {
                        if (array == null)
                                throw new ArgumentNullException ("array");
-                       if (index < 0)
-                               throw new ArgumentOutOfRangeException ("index");
-                       if (index > array.Length)
+                       if (arrayIndex < 0)
+                               throw new ArgumentOutOfRangeException ("arrayIndex");
+                       if (arrayIndex > array.Length)
                                throw new ArgumentException ("index larger than largest valid index of array");
-                       if (array.Length - index < count)
+                       if (array.Length - arrayIndex < count)
                                throw new ArgumentException ("Destination array cannot hold the requested elements!");
 
                        for (int i = 0, items = 0; i < touched && items < count; i++) {
                                if (GetLinkHashCode (i) != 0)
-                                       array [index++] = slots [i];
+                                       array [arrayIndex++] = slots [i];
                        }
                }
 
@@ -352,24 +352,21 @@ namespace System.Collections.Generic {
                        return true;
                }
 
-               public int RemoveWhere (Predicate<T> predicate)
+               public int RemoveWhere (Predicate<T> match)
                {
-                       if (predicate == null)
-                               throw new ArgumentNullException ("predicate");
+                       if (match == null)
+                               throw new ArgumentNullException ("match");
 
-                       int counter = 0;
+                       var candidates = new List<T> ();
 
-                       var copy = new T [count];
-                       CopyTo (copy, 0);
+                       foreach (var item in this)
+                               if (match (item)) 
+                                       candidates.Add (item);
 
-                       foreach (var item in copy) {
-                               if (predicate (item)) {
-                                       Remove (item);
-                                       counter++;
-                               }
-                       }
+                       foreach (var item in candidates)
+                               Remove (item);
 
-                       return counter;
+                       return candidates.Count;
                }
 
                public void TrimExcess ()
@@ -384,16 +381,9 @@ namespace System.Collections.Generic {
                        if (other == null)
                                throw new ArgumentNullException ("other");
 
-                       var copy = new T [count];
-                       CopyTo (copy, 0);
+                       var other_set = ToSet (other);
 
-                       foreach (var item in copy)
-                               if (!other.Contains (item))
-                                       Remove (item);
-
-                       foreach (var item in other)
-                               if (!Contains (item))
-                                       Remove (item);
+                       RemoveWhere (item => !other_set.Contains (item));
                }
 
                public void ExceptWith (IEnumerable<T> other)
@@ -422,11 +412,13 @@ namespace System.Collections.Generic {
                        if (other == null)
                                throw new ArgumentNullException ("other");
 
-                       if (count != other.Count ())
+                       var other_set = ToSet (other);
+
+                       if (count != other_set.Count)
                                return false;
 
                        foreach (var item in this)
-                               if (!other.Contains (item))
+                               if (!other_set.Contains (item))
                                        return false;
 
                        return true;
@@ -437,12 +429,18 @@ namespace System.Collections.Generic {
                        if (other == null)
                                throw new ArgumentNullException ("other");
 
-                       foreach (var item in other) {
-                               if (Contains (item))
+                       foreach (var item in ToSet (other))
+                               if (!Add (item))
                                        Remove (item);
-                               else
-                                       Add (item);
-                       }
+               }
+
+               HashSet<T> ToSet (IEnumerable<T> enumerable)
+               {
+                       var set = enumerable as HashSet<T>;
+                       if (set == null || !Comparer.Equals (set.Comparer))
+                               set = new HashSet<T> (enumerable, Comparer);
+
+                       return set;
                }
 
                public void UnionWith (IEnumerable<T> other)
@@ -454,7 +452,7 @@ namespace System.Collections.Generic {
                                Add (item);
                }
 
-               bool CheckIsSubsetOf (IEnumerable<T> other)
+               bool CheckIsSubsetOf (HashSet<T> other)
                {
                        if (other == null)
                                throw new ArgumentNullException ("other");
@@ -474,10 +472,12 @@ namespace System.Collections.Generic {
                        if (count == 0)
                                return true;
 
-                       if (count > other.Count ())
+                       var other_set = ToSet (other);
+
+                       if (count > other_set.Count)
                                return false;
 
-                       return CheckIsSubsetOf (other);
+                       return CheckIsSubsetOf (other_set);
                }
 
                public bool IsProperSubsetOf (IEnumerable<T> other)
@@ -488,13 +488,15 @@ namespace System.Collections.Generic {
                        if (count == 0)
                                return true;
 
-                       if (count >= other.Count ())
+                       var other_set = ToSet (other);
+
+                       if (count >= other_set.Count)
                                return false;
 
-                       return CheckIsSubsetOf (other);
+                       return CheckIsSubsetOf (other_set);
                }
 
-               bool CheckIsSupersetOf (IEnumerable<T> other)
+               bool CheckIsSupersetOf (HashSet<T> other)
                {
                        if (other == null)
                                throw new ArgumentNullException ("other");
@@ -511,10 +513,12 @@ namespace System.Collections.Generic {
                        if (other == null)
                                throw new ArgumentNullException ("other");
 
-                       if (count < other.Count ())
+                       var other_set = ToSet (other);
+
+                       if (count < other_set.Count)
                                return false;
 
-                       return CheckIsSupersetOf (other);
+                       return CheckIsSupersetOf (other_set);
                }
 
                public bool IsProperSupersetOf (IEnumerable<T> other)
@@ -522,34 +526,97 @@ namespace System.Collections.Generic {
                        if (other == null)
                                throw new ArgumentNullException ("other");
 
-                       if (count <= other.Count ())
+                       var other_set = ToSet (other);
+
+                       if (count <= other_set.Count)
                                return false;
 
-                       return CheckIsSupersetOf (other);
+                       return CheckIsSupersetOf (other_set);
                }
 
-               [MonoTODO]
+               class HashSetEqualityComparer : IEqualityComparer<HashSet<T>>
+               {
+                       public bool Equals (HashSet<T> lhs, HashSet<T> rhs)
+                       {
+                               if (lhs == rhs)
+                                       return true;
+
+                               if (lhs == null || rhs == null || lhs.Count != rhs.Count)
+                                       return false;
+
+                               foreach (var item in lhs)
+                                       if (!rhs.Contains (item))
+                                               return false;
+
+                               return true;
+                       }
+
+                       public int GetHashCode (HashSet<T> hashset)
+                       {
+                               if (hashset == null)
+                                       return 0;
+
+                               IEqualityComparer<T> comparer = EqualityComparer<T>.Default;
+                               int hash = 0;
+                               foreach (var item in hashset)
+                                       hash ^= comparer.GetHashCode (item);
+
+                               return hash;
+                       }
+               }
+
+               static readonly HashSetEqualityComparer setComparer = new HashSetEqualityComparer ();
+
                public static IEqualityComparer<HashSet<T>> CreateSetComparer ()
                {
-                       throw new NotImplementedException ();
+                       return setComparer;
                }
 
-               [MonoTODO]
                [SecurityPermission (SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
                public virtual void GetObjectData (SerializationInfo info, StreamingContext context)
                {
-                       throw new NotImplementedException ();
+                       if (info == null) {
+                               throw new ArgumentNullException("info");
+                       }
+                       info.AddValue("Version", generation);
+                       info.AddValue("Comparer", comparer, typeof(IEqualityComparer<T>));
+                       info.AddValue("Capacity", (table == null) ? 0 : table.Length);
+                       if (table != null) {
+                               T[] tableArray = new T[table.Length];
+                               CopyTo(tableArray);
+                               info.AddValue("Elements", tableArray, typeof(T[]));
+                       }
                }
 
-               [MonoTODO]
                public virtual void OnDeserialization (object sender)
                {
-                       if (si == null)
-                               return;
+                       if (si != null)
+                       {
+                               generation = (int) si.GetValue("Version", typeof(int));
+                               comparer = (IEqualityComparer<T>) si.GetValue("Comparer", 
+                                                                             typeof(IEqualityComparer<T>));
+                               int capacity = (int) si.GetValue("Capacity", typeof(int));
+
+                               empty_slot = NO_SLOT;
+                               if (capacity > 0) {
+                                       table = new int[capacity];
+                                       slots = new T[capacity];
+
+                                       T[] tableArray = (T[]) si.GetValue("Elements", typeof(T[]));
+                                       if (tableArray == null) 
+                                               throw new SerializationException("Missing Elements");
+
+                                       for (int iElement = 0; iElement < tableArray.Length; iElement++) {
+                                               Add(tableArray[iElement]);
+                                       }
+                               } else 
+                                       table = null;
 
-                       throw new NotImplementedException ();
+                               si = null;
+                       }
                }
 
+
                IEnumerator<T> IEnumerable<T>.GetEnumerator ()
                {
                        return new Enumerator (this);
@@ -559,11 +626,6 @@ namespace System.Collections.Generic {
                        get { return false; }
                }
 
-               void ICollection<T>.CopyTo (T [] array, int index)
-               {
-                       CopyTo (array, index);
-               }
-
                void ICollection<T>.Add (T item)
                {
                        Add (item);