perf: Significant IcdHashSet optimizations

This commit is contained in:
Chris Cameron
2018-10-27 20:36:22 -04:00
parent e01bc9ede6
commit 5cec0e10f1
3 changed files with 45 additions and 40 deletions

View File

@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
## [Unreleased] ## [Unreleased]
### Changed ### Changed
- Micro-optimizations in string and XML manipulations - Micro-optimizations in string and XML manipulations
- Significant hashset optimizations
## [6.0.0] - 2018-10-18 ## [6.0.0] - 2018-10-18
### Added ### Added

View File

@@ -8,12 +8,6 @@ namespace ICD.Common.Utils.Tests.Collections
[TestFixture] [TestFixture]
public sealed class IcdHashSetTest public sealed class IcdHashSetTest
{ {
[Test, UsedImplicitly]
public void NullSetTest()
{
Assert.AreEqual(0, IcdHashSet<int>.NullSet.Count);
}
[Test, UsedImplicitly] [Test, UsedImplicitly]
public void CountTest() public void CountTest()
{ {

View File

@@ -16,12 +16,6 @@ namespace ICD.Common.Utils.Collections
#region Properties #region Properties
/// <summary>
/// Returns a new, empty hashset.
/// </summary>
[PublicAPI]
public static IcdHashSet<T> NullSet { get { return new IcdHashSet<T>(); } }
/// <summary> /// <summary>
/// Gets the number of items contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>. /// Gets the number of items contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>.
/// </summary> /// </summary>
@@ -98,11 +92,10 @@ namespace ICD.Common.Utils.Collections
[PublicAPI] [PublicAPI]
public IcdHashSet<T> Union(IEnumerable<T> set) public IcdHashSet<T> Union(IEnumerable<T> set)
{ {
IcdHashSet<T> unionSet = new IcdHashSet<T>(this);
if (set == null) if (set == null)
return unionSet; throw new ArgumentNullException("set");
IcdHashSet<T> unionSet = new IcdHashSet<T>(this);
unionSet.AddRange(set); unionSet.AddRange(set);
return unionSet; return unionSet;
@@ -116,10 +109,10 @@ namespace ICD.Common.Utils.Collections
[PublicAPI] [PublicAPI]
public IcdHashSet<T> Subtract(IEnumerable<T> set) public IcdHashSet<T> Subtract(IEnumerable<T> set)
{ {
IcdHashSet<T> subtractSet = new IcdHashSet<T>(this);
if (set == null) if (set == null)
return subtractSet; throw new ArgumentNullException("set");
IcdHashSet<T> subtractSet = new IcdHashSet<T>(this);
foreach (T item in set) foreach (T item in set)
subtractSet.Remove(item); subtractSet.Remove(item);
@@ -133,17 +126,14 @@ namespace ICD.Common.Utils.Collections
/// <param name="set"></param> /// <param name="set"></param>
/// <returns></returns> /// <returns></returns>
[PublicAPI] [PublicAPI]
public IcdHashSet<T> Intersection(IcdHashSet<T> set) public IcdHashSet<T> Intersection(IEnumerable<T> set)
{ {
IcdHashSet<T> intersectionSet = NullSet;
if (set == null) if (set == null)
return intersectionSet; throw new ArgumentNullException("set");
foreach (T item in this.Where(set.Contains)) IcdHashSet<T> intersectionSet = new IcdHashSet<T>();
intersectionSet.Add(item);
foreach (T item in set.Where(Contains)) foreach (T item in set.Where(item => Contains(item)))
intersectionSet.Add(item); intersectionSet.Add(item);
return intersectionSet; return intersectionSet;
@@ -155,11 +145,22 @@ namespace ICD.Common.Utils.Collections
/// <param name="set"></param> /// <param name="set"></param>
/// <returns></returns> /// <returns></returns>
[PublicAPI] [PublicAPI]
public IcdHashSet<T> NonIntersection(IcdHashSet<T> set) public IcdHashSet<T> NonIntersection(IEnumerable<T> set)
{ {
IcdHashSet<T> setToCompare = set ?? NullSet; if (set == null)
throw new ArgumentNullException("set");
return Subtract(set).Union(setToCompare.Subtract(this)); IcdHashSet<T> output = new IcdHashSet<T>(this);
foreach (T item in set)
{
if (output.Contains(item))
output.Remove(item);
else
output.Add(item);
}
return output;
} }
/// <summary> /// <summary>
@@ -170,9 +171,10 @@ namespace ICD.Common.Utils.Collections
[PublicAPI] [PublicAPI]
public bool IsSubsetOf(IcdHashSet<T> set) public bool IsSubsetOf(IcdHashSet<T> set)
{ {
IcdHashSet<T> setToCompare = set ?? NullSet; if (set == null)
throw new ArgumentNullException("set");
return this.All(setToCompare.Contains); return Count <= set.Count && this.All(set.Contains);
} }
/// <summary> /// <summary>
@@ -183,9 +185,10 @@ namespace ICD.Common.Utils.Collections
[PublicAPI] [PublicAPI]
public bool IsProperSubsetOf(IcdHashSet<T> set) public bool IsProperSubsetOf(IcdHashSet<T> set)
{ {
IcdHashSet<T> setToCompare = set ?? NullSet; if (set == null)
throw new ArgumentNullException("set");
return IsSubsetOf(setToCompare) && !setToCompare.IsSubsetOf(this); return Count < set.Count && IsSubsetOf(set);
} }
/// <summary> /// <summary>
@@ -196,9 +199,10 @@ namespace ICD.Common.Utils.Collections
[PublicAPI] [PublicAPI]
public bool IsSupersetOf(IcdHashSet<T> set) public bool IsSupersetOf(IcdHashSet<T> set)
{ {
IcdHashSet<T> setToCompare = set ?? NullSet; if (set == null)
throw new ArgumentNullException("set");
return setToCompare.IsSubsetOf(this); return set.IsSubsetOf(this);
} }
/// <summary> /// <summary>
@@ -209,9 +213,10 @@ namespace ICD.Common.Utils.Collections
[PublicAPI] [PublicAPI]
public bool IsProperSupersetOf(IcdHashSet<T> set) public bool IsProperSupersetOf(IcdHashSet<T> set)
{ {
IcdHashSet<T> setToCompare = set ?? NullSet; if (set == null)
throw new ArgumentNullException("set");
return IsSupersetOf(setToCompare) && !setToCompare.IsSupersetOf(this); return set.IsProperSubsetOf(this);
} }
/// <summary> /// <summary>
@@ -222,9 +227,10 @@ namespace ICD.Common.Utils.Collections
[PublicAPI] [PublicAPI]
public bool SetEquals(IcdHashSet<T> set) public bool SetEquals(IcdHashSet<T> set)
{ {
IcdHashSet<T> setToCompare = set ?? NullSet; if (set == null)
return Count == 0;
return IsSupersetOf(setToCompare) && setToCompare.IsSupersetOf(this); return Count == set.Count && set.All(item => Contains(item));
} }
#endregion #endregion
@@ -238,9 +244,7 @@ namespace ICD.Common.Utils.Collections
/// <returns></returns> /// <returns></returns>
public bool Add(T item) public bool Add(T item)
{ {
// ReSharper disable CompareNonConstrainedGenericWithNull
if (item == null) if (item == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
throw new ArgumentNullException("item"); throw new ArgumentNullException("item");
if (m_Dict.ContainsKey(item)) if (m_Dict.ContainsKey(item))
@@ -288,6 +292,9 @@ namespace ICD.Common.Utils.Collections
/// <returns></returns> /// <returns></returns>
public bool Contains(T item) public bool Contains(T item)
{ {
if (item == null)
throw new ArgumentNullException("item");
return m_Dict.ContainsKey(item); return m_Dict.ContainsKey(item);
} }
@@ -309,6 +316,9 @@ namespace ICD.Common.Utils.Collections
/// <param name="item">The object to remove from the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.</exception> /// <param name="item">The object to remove from the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.</exception>
public bool Remove(T item) public bool Remove(T item)
{ {
if (item == null)
throw new ArgumentNullException("item");
return m_Dict.Remove(item); return m_Dict.Remove(item);
} }