From 482c31b4218dc568f52250fb7884d0deb6f8845d Mon Sep 17 00:00:00 2001 From: maximv Date: Tue, 3 Nov 2020 23:08:57 +0300 Subject: [PATCH] #35 remove in ConflictsEntry --- src/ImTools/ImTools.Experimental.cs | 75 ++++++++++++++----- .../Experimental.ImMap234Tests.cs | 3 + 2 files changed, 61 insertions(+), 17 deletions(-) diff --git a/src/ImTools/ImTools.Experimental.cs b/src/ImTools/ImTools.Experimental.cs index bd97c6e1..0494b303 100644 --- a/src/ImTools/ImTools.Experimental.cs +++ b/src/ImTools/ImTools.Experimental.cs @@ -1936,11 +1936,14 @@ protected ImHashMap234() { } /// Pretty-prints public override string ToString() => "empty"; + /// Lookup for the entry, if not found returns `null` + public virtual ValueEntry GetEntryOrDefault(int hash, K key) => null; + /// Produces the new or updated map with the new entry public virtual ImHashMap234 AddOrUpdateEntry(int hash, ValueEntry entry) => entry; - /// Lookup for the entry, if not found returns `null` - public virtual ValueEntry GetEntryOrDefault(int hash, K key) => null; + /// Returns the map without the entry with the specified hash and key if it is found in the map + public virtual ImHashMap234 RemoveEntry(int hash, K key) => this; /// The base entry for the Value and for the ConflictingValues entries, contains the Hash and Key public abstract class Entry : ImHashMap234 @@ -1983,6 +1986,10 @@ public override ImHashMap234 AddOrUpdateEntry(int hash, ValueEntry entry) // hash < Hash ? new Leaf2(entry, this) : ReferenceEquals(Key, entry.Key) || Key.Equals(entry.Key) ? (ImHashMap234)entry : new ConflictsEntry(hash, this, entry); + + /// + public override ImHashMap234 RemoveEntry(int hash, K key) => + hash == Hash && Key.Equals(key) ? Empty : this; } /// Entry containing the Array of conflicting Value entries. @@ -2026,28 +2033,53 @@ public override ImHashMap234 AddOrUpdateEntry(int hash, ValueEntry entry) var key = entry.Key; - var conflicts = Conflicts; - var conflictCount = conflicts.Length; - var conflictIndex = conflictCount - 1; - while (conflictIndex != -1 && !key.Equals(conflicts[conflictIndex].Key)) - --conflictIndex; + var cs = Conflicts; + var n = cs.Length; + var i = n - 1; + while (i != -1 && !key.Equals(cs[i].Key)) --i; ValueEntry[] newConflicts; - if (conflictIndex != -1) // update the found (existing) conflicted value + if (i != -1) // update the found (existing) conflicted value { - newConflicts = new ValueEntry[conflictCount]; - Array.Copy(conflicts, 0, newConflicts, 0, conflictCount); - newConflicts[conflictIndex] = entry; + newConflicts = new ValueEntry[n]; + Array.Copy(cs, 0, newConflicts, 0, n); + newConflicts[i] = entry; } else // add the new conflicting value { - newConflicts = new ValueEntry[conflictCount + 1]; - Array.Copy(conflicts, 0, newConflicts, 0, conflictCount); - newConflicts[conflictCount] = entry; + newConflicts = new ValueEntry[n + 1]; + Array.Copy(cs, 0, newConflicts, 0, n); + newConflicts[n] = entry; } return new ConflictsEntry(hash, newConflicts); } + + /// + public override ImHashMap234 RemoveEntry(int hash, K key) + { + if (hash != Hash) + return this; + + var cs = Conflicts; + var n = cs.Length; + var i = n - 1; + while (i != -1 && !key.Equals(cs[i].Key)) --i; + if (i != -1) + { + if (n == 2) + return i == 0 ? cs[1] : cs[0]; + + var newConflicts = new ValueEntry[n -= 1]; // the new n is less by one + if (i > 0) // copy the first part + Array.Copy(cs, 0, newConflicts, 0, i); + if (i < n) // copy the first part + Array.Copy(cs, i + 1, newConflicts, i, n - i); + + return new ConflictsEntry(hash, newConflicts); + } + return this; + } } } @@ -2070,14 +2102,23 @@ public static V GetValueOrDefault(this ImHashMap234 map, K key) => /// Adds or updates the value by key in the map, always returning the modified map. [MethodImpl((MethodImplOptions)256)] public static ImHashMap234 AddOrUpdate(this ImHashMap234 map, int hash, K key, V value) => - map == ImHashMap234.Empty - ? new ImHashMap234.ValueEntry(hash, key, value) - : map.AddOrUpdateEntry(hash, new ImHashMap234.ValueEntry(hash, key, value)); + map == ImHashMap234.Empty ? new ImHashMap234.ValueEntry(hash, key, value) : + map.AddOrUpdateEntry(hash, new ImHashMap234.ValueEntry(hash, key, value)); /// Adds or updates the value by key in the map, always returning the modified map. [MethodImpl((MethodImplOptions)256)] public static ImHashMap234 AddOrUpdate(this ImHashMap234 map, K key, V value) => map.AddOrUpdate(key.GetHashCode(), key, value); + + /// Returns the map without the entry with the specified hash and key if it is found in the map. + [MethodImpl((MethodImplOptions)256)] + public static ImHashMap234 Remove(this ImHashMap234 map, int hash, K key) => + map == ImHashMap234.Empty ? map : map.RemoveEntry(hash, key); + + /// Returns the map without the entry with the specified hash and key if it is found in the map. + [MethodImpl((MethodImplOptions)256)] + public static ImHashMap234 Remove(this ImHashMap234 map, K key) => + map == ImHashMap234.Empty ? map : map.RemoveEntry(key.GetHashCode(), key); } /// The base class for the tree leafs and branches, also defines the Empty tree diff --git a/test/ImTools.UnitTests/Experimental.ImMap234Tests.cs b/test/ImTools.UnitTests/Experimental.ImMap234Tests.cs index 86dcfec0..4cb9006f 100644 --- a/test/ImTools.UnitTests/Experimental.ImMap234Tests.cs +++ b/test/ImTools.UnitTests/Experimental.ImMap234Tests.cs @@ -18,6 +18,9 @@ public void Adding_hash_and_keys_from_1_to_10_and_checking_the_tree_shape_on_eac Assert.IsInstanceOf.ValueEntry>(m); Assert.AreEqual("a", m.GetValueOrDefault(1)); Assert.AreEqual(null, m.GetValueOrDefault(10)); + + var mr = m.Remove(1); + Assert.AreSame(ImHashMap234.Empty, mr); } [Test]