From 5cec0e10f14fa0ea177f801e2fe9c42e63aa0479 Mon Sep 17 00:00:00 2001 From: Chris Cameron Date: Sat, 27 Oct 2018 20:36:22 -0400 Subject: [PATCH] perf: Significant IcdHashSet optimizations --- CHANGELOG.md | 1 + .../Collections/IcdHashSetTest.cs | 6 -- ICD.Common.Utils/Collections/IcdHashSet.cs | 78 +++++++++++-------- 3 files changed, 45 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4081fc..4cf9ae7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] ### Changed - Micro-optimizations in string and XML manipulations + - Significant hashset optimizations ## [6.0.0] - 2018-10-18 ### Added diff --git a/ICD.Common.Utils.Tests/Collections/IcdHashSetTest.cs b/ICD.Common.Utils.Tests/Collections/IcdHashSetTest.cs index f5a0dc8..f082b5e 100644 --- a/ICD.Common.Utils.Tests/Collections/IcdHashSetTest.cs +++ b/ICD.Common.Utils.Tests/Collections/IcdHashSetTest.cs @@ -8,12 +8,6 @@ namespace ICD.Common.Utils.Tests.Collections [TestFixture] public sealed class IcdHashSetTest { - [Test, UsedImplicitly] - public void NullSetTest() - { - Assert.AreEqual(0, IcdHashSet.NullSet.Count); - } - [Test, UsedImplicitly] public void CountTest() { diff --git a/ICD.Common.Utils/Collections/IcdHashSet.cs b/ICD.Common.Utils/Collections/IcdHashSet.cs index ec62db7..1bffedd 100644 --- a/ICD.Common.Utils/Collections/IcdHashSet.cs +++ b/ICD.Common.Utils/Collections/IcdHashSet.cs @@ -16,12 +16,6 @@ namespace ICD.Common.Utils.Collections #region Properties - /// - /// Returns a new, empty hashset. - /// - [PublicAPI] - public static IcdHashSet NullSet { get { return new IcdHashSet(); } } - /// /// Gets the number of items contained in the . /// @@ -98,11 +92,10 @@ namespace ICD.Common.Utils.Collections [PublicAPI] public IcdHashSet Union(IEnumerable set) { - IcdHashSet unionSet = new IcdHashSet(this); - if (set == null) - return unionSet; + throw new ArgumentNullException("set"); + IcdHashSet unionSet = new IcdHashSet(this); unionSet.AddRange(set); return unionSet; @@ -116,10 +109,10 @@ namespace ICD.Common.Utils.Collections [PublicAPI] public IcdHashSet Subtract(IEnumerable set) { - IcdHashSet subtractSet = new IcdHashSet(this); - if (set == null) - return subtractSet; + throw new ArgumentNullException("set"); + + IcdHashSet subtractSet = new IcdHashSet(this); foreach (T item in set) subtractSet.Remove(item); @@ -133,17 +126,14 @@ namespace ICD.Common.Utils.Collections /// /// [PublicAPI] - public IcdHashSet Intersection(IcdHashSet set) + public IcdHashSet Intersection(IEnumerable set) { - IcdHashSet intersectionSet = NullSet; - if (set == null) - return intersectionSet; + throw new ArgumentNullException("set"); - foreach (T item in this.Where(set.Contains)) - intersectionSet.Add(item); + IcdHashSet intersectionSet = new IcdHashSet(); - foreach (T item in set.Where(Contains)) + foreach (T item in set.Where(item => Contains(item))) intersectionSet.Add(item); return intersectionSet; @@ -155,11 +145,22 @@ namespace ICD.Common.Utils.Collections /// /// [PublicAPI] - public IcdHashSet NonIntersection(IcdHashSet set) + public IcdHashSet NonIntersection(IEnumerable set) { - IcdHashSet setToCompare = set ?? NullSet; + if (set == null) + throw new ArgumentNullException("set"); - return Subtract(set).Union(setToCompare.Subtract(this)); + IcdHashSet output = new IcdHashSet(this); + + foreach (T item in set) + { + if (output.Contains(item)) + output.Remove(item); + else + output.Add(item); + } + + return output; } /// @@ -170,9 +171,10 @@ namespace ICD.Common.Utils.Collections [PublicAPI] public bool IsSubsetOf(IcdHashSet set) { - IcdHashSet setToCompare = set ?? NullSet; + if (set == null) + throw new ArgumentNullException("set"); - return this.All(setToCompare.Contains); + return Count <= set.Count && this.All(set.Contains); } /// @@ -183,9 +185,10 @@ namespace ICD.Common.Utils.Collections [PublicAPI] public bool IsProperSubsetOf(IcdHashSet set) { - IcdHashSet setToCompare = set ?? NullSet; + if (set == null) + throw new ArgumentNullException("set"); - return IsSubsetOf(setToCompare) && !setToCompare.IsSubsetOf(this); + return Count < set.Count && IsSubsetOf(set); } /// @@ -196,9 +199,10 @@ namespace ICD.Common.Utils.Collections [PublicAPI] public bool IsSupersetOf(IcdHashSet set) { - IcdHashSet setToCompare = set ?? NullSet; + if (set == null) + throw new ArgumentNullException("set"); - return setToCompare.IsSubsetOf(this); + return set.IsSubsetOf(this); } /// @@ -209,9 +213,10 @@ namespace ICD.Common.Utils.Collections [PublicAPI] public bool IsProperSupersetOf(IcdHashSet set) { - IcdHashSet setToCompare = set ?? NullSet; + if (set == null) + throw new ArgumentNullException("set"); - return IsSupersetOf(setToCompare) && !setToCompare.IsSupersetOf(this); + return set.IsProperSubsetOf(this); } /// @@ -222,9 +227,10 @@ namespace ICD.Common.Utils.Collections [PublicAPI] public bool SetEquals(IcdHashSet set) { - IcdHashSet 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 @@ -238,9 +244,7 @@ namespace ICD.Common.Utils.Collections /// public bool Add(T item) { - // ReSharper disable CompareNonConstrainedGenericWithNull if (item == null) - // ReSharper restore CompareNonConstrainedGenericWithNull throw new ArgumentNullException("item"); if (m_Dict.ContainsKey(item)) @@ -288,6 +292,9 @@ namespace ICD.Common.Utils.Collections /// public bool Contains(T item) { + if (item == null) + throw new ArgumentNullException("item"); + return m_Dict.ContainsKey(item); } @@ -309,6 +316,9 @@ namespace ICD.Common.Utils.Collections /// The object to remove from the .The is read-only. public bool Remove(T item) { + if (item == null) + throw new ArgumentNullException("item"); + return m_Dict.Remove(item); }