Skip to content

Commit

Permalink
Branch2 AddOrKeep #35; lookup marks
Browse files Browse the repository at this point in the history
  • Loading branch information
maximv committed Nov 7, 2020
1 parent 2f00459 commit f9fa692
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 33 deletions.
12 changes: 6 additions & 6 deletions playground/ImTools.Benchmarks/ImHashMapBenchmarks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -880,13 +880,13 @@ public class Lookup
| Method | Count | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
|------------------------------- |------ |----------:|----------:|----------:|------:|--------:|------:|------:|------:|----------:|
| ImHashMap_TryFind | 1 | 7.741 ns | 0.3234 ns | 0.9435 ns | 1.00 | 0.00 | - | - | - | - |
| Experimental_ImHashMap_TryFind | 1 | 9.964 ns | 0.3488 ns | 0.9370 ns | 1.31 | 0.20 | - | - | - | - |
| ImHashMap234_TryFind | 1 | 7.620 ns | 0.3250 ns | 0.9376 ns | 1.00 | 0.18 | - | - | - | - |
| ImHashMap_TryFind | 1 | 5.329 ns | 0.1344 ns | 0.1122 ns | 1.00 | 0.00 | - | - | - | - |
| Experimental_ImHashMap_TryFind | 1 | 6.736 ns | 0.0890 ns | 0.0832 ns | 1.26 | 0.04 | - | - | - | - |
| ImHashMap234_TryFind | 1 | 4.877 ns | 0.0959 ns | 0.0850 ns | 0.92 | 0.03 | - | - | - | - |
| | | | | | | | | | | |
| ImHashMap_TryFind | 10 | 11.255 ns | 0.3801 ns | 0.9813 ns | 1.00 | 0.00 | - | - | - | - |
| Experimental_ImHashMap_TryFind | 10 | 15.733 ns | 0.4537 ns | 1.1129 ns | 1.41 | 0.16 | - | - | - | - |
| ImHashMap234_TryFind | 10 | 10.676 ns | 0.3391 ns | 0.9167 ns | 0.96 | 0.12 | - | - | - | - |
| ImHashMap_TryFind | 10 | 8.150 ns | 0.1318 ns | 0.1233 ns | 1.00 | 0.00 | - | - | - | - |
| Experimental_ImHashMap_TryFind | 10 | 11.704 ns | 0.2382 ns | 0.2229 ns | 1.44 | 0.03 | - | - | - | - |
| ImHashMap234_TryFind | 10 | 6.332 ns | 0.0824 ns | 0.0730 ns | 0.78 | 0.01 | - | - | - | - |
*/
[Params(1, 10)]//, 100, 1_000)]// the 1000 does not add anything as the LookupKey stored higher in the tree, 1000)]
Expand Down
117 changes: 90 additions & 27 deletions src/ImTools/ImTools.Experimental.234.cs
Original file line number Diff line number Diff line change
Expand Up @@ -625,11 +625,11 @@ internal Leaf AddOrUpdateOrSplitEntry(int hash, ValueEntry entry, out Entry popE
popEntry = null;
popRight = null;
return
hash == e0.Hash ? new Leaf5(e0.Update(entry), e1, e2, e3, e4) :
hash == e1.Hash ? new Leaf5(e0, e1.Update(entry), e2, e3, e4) :
hash == e2.Hash ? new Leaf5(e0, e1, e2.Update(entry), e3, e4) :
hash == e3.Hash ? new Leaf5(e0, e1, e3, e2.Update(entry), e4) :
new Leaf5(e0, e1, e2, e3, e4.Update(entry));
hash == e0.Hash ? new Leaf5(e0.Update(entry), e1, e2, e3, e4) :
hash == e1.Hash ? new Leaf5(e0, e1.Update(entry), e2, e3, e4) :
hash == e2.Hash ? new Leaf5(e0, e1, e2.Update(entry), e3, e4) :
hash == e3.Hash ? new Leaf5(e0, e1, e3, e2.Update(entry), e4) :
new Leaf5(e0, e1, e2, e3, e4.Update(entry));
}

/// <inheritdoc />
Expand Down Expand Up @@ -671,7 +671,7 @@ public override ImHashMap234<K, V> AddOrKeepEntry(int hash, ValueEntry entry)
/// The same as `AddOrKeepEntry` but instead of constructing the new map it returns the parts: return value is the Left node,
/// `ref Entry entry` (always passed as ValueEntry) will be set to the middle entry, and `popRight` is the right node.
/// </summary>
internal Leaf AddOrKeepOrSplitEntry(int hash, ref Entry entry, out Leaf popRight)
internal Leaf AddOrKeepOrSplitEntry(int hash, ValueEntry entry, out Entry popEntry, out Leaf popRight)
{
var e0 = Entry0;
var e1 = Entry1;
Expand All @@ -681,55 +681,54 @@ internal Leaf AddOrKeepOrSplitEntry(int hash, ref Entry entry, out Leaf popRight

if (hash > e4.Hash)
{
popEntry = e3;
popRight = new Leaf2(e4, entry);
entry = e3;
return new Leaf3(e0, e1, e2);
}

if (hash < e0.Hash)
{
var left = new Leaf2(entry, e0);
entry = e1;
popEntry = e1;
popRight = new Leaf3(e2, e3, e4);
return left;
return new Leaf2(entry, e0);
}

if (hash > e0.Hash && hash < e1.Hash)
{
var left = new Leaf2(e0, entry);
entry = e1;
popEntry = e1;
popRight = new Leaf3(e2, e3, e4);
return left;
return new Leaf2(e0, entry);
}

if (hash > e1.Hash && hash < e2.Hash)
{
// the entry is kept as-is
popEntry = entry;
popRight = new Leaf3(e2, e3, e4);
return new Leaf2(e0, e1);
}

if (hash > e2.Hash && hash < e3.Hash)
{
// the entry is kept as-is
popEntry = entry;
popRight = new Leaf2(e3, e4);
return new Leaf3(e0, e1, e2);
}

if (hash > e3.Hash && hash < e4.Hash)
{
popEntry = e3;
popRight = new Leaf2(entry, e4);
entry = e3;
return new Leaf3(e0, e1, e2);
}

popEntry = null;
popRight = null;
return
hash == e0.Hash ? ((e0 = e0.Keep((ValueEntry)entry)) == Entry0 ? this : new Leaf5(e0, e1, e2, e3, e4)) :
hash == e1.Hash ? ((e1 = e1.Keep((ValueEntry)entry)) == Entry1 ? this : new Leaf5(e0, e1, e2, e3, e4)) :
hash == e2.Hash ? ((e2 = e2.Keep((ValueEntry)entry)) == Entry2 ? this : new Leaf5(e0, e1, e2, e3, e4)) :
hash == e3.Hash ? ((e3 = e3.Keep((ValueEntry)entry)) == Entry3 ? this : new Leaf5(e0, e1, e2, e3, e4)) :
((e4 = e4.Keep((ValueEntry)entry)) == Entry4 ? this : new Leaf5(e0, e1, e2, e3, e4));
hash == e0.Hash ? ((e0 = e0.Keep(entry)) == Entry0 ? this : new Leaf5(e0, e1, e2, e3, e4)) :
hash == e1.Hash ? ((e1 = e1.Keep(entry)) == Entry1 ? this : new Leaf5(e0, e1, e2, e3, e4)) :
hash == e2.Hash ? ((e2 = e2.Keep(entry)) == Entry2 ? this : new Leaf5(e0, e1, e2, e3, e4)) :
hash == e3.Hash ? ((e3 = e3.Keep(entry)) == Entry3 ? this : new Leaf5(e0, e1, e2, e3, e4)) :
((e4 = e4.Keep(entry)) == Entry4 ? this : new Leaf5(e0, e1, e2, e3, e4));
}

/// <inheritdoc />
Expand Down Expand Up @@ -840,11 +839,52 @@ public override ImHashMap234<K, V> AddOrUpdateEntry(int hash, ValueEntry entry)

return new Branch2Leafs(Left, e0.Update(entry), Right);
}

/// <inheritdoc />
public override ImHashMap234<K, V> AddOrKeepEntry(int hash, ValueEntry entry)
{
var e0 = Entry0;
if (hash > e0.Hash)
{
Leaf newRight;
if (Right is Leaf5 l5)
{
newRight = l5.AddOrKeepOrSplitEntry(hash, entry, out var popEntry, out var popRight);
if (newRight == l5)
return this;
if (popRight != null)
return new Branch3Leafs(Left, e0, newRight, popEntry, popRight);
return new Branch2Leafs(Left, e0, newRight);
}

newRight = (Leaf)Right.AddOrKeepEntry(hash, entry);
return newRight == Right ? this : new Branch2Leafs(Left, e0, newRight);
}

if (hash < e0.Hash)
{
Leaf newLeft;
if (Left is Leaf5 l5)
{
newLeft = l5.AddOrUpdateOrSplitEntry(hash, entry, out var popEntry, out var popRight);
if (newLeft == l5)
return this;
if (popRight != null)
return new Branch3Leafs(newLeft, popEntry, popRight, e0, Right);
return new Branch2Leafs(newLeft, e0, Right);
}

newLeft = (Leaf)Left.AddOrKeepEntry(hash, entry);
return newLeft == Left ? this : new Branch2Leafs(newLeft, e0, Right);
}

return (e0 = e0.Keep(entry)) == Entry0 ? this : new Branch2Leafs(Left, e0, Right);
}
}

/// <summary>Branch of 3 leafs and two entries</summary>
public sealed class Branch3Leafs : Branch
{
{
/// <summary>Left entry</summary>
public readonly Entry Entry0;
/// <summary>Right entry</summary>
Expand Down Expand Up @@ -985,7 +1025,8 @@ public override string ToString() =>
/// <summary>ImMap methods</summary>
public static class ImHashMap234
{
/// <summary>Looks up for the key using its hash code and returns found value or the default value if not found</summary>
/// <summary>Looks up for the key using its hash code and checking the key with `object.Equals` for equality,
/// returns found value or the default value if not found</summary>
[MethodImpl((MethodImplOptions)256)]
public static V GetValueOrDefault<K, V>(this ImHashMap234<K, V> map, int hash, K key)
{
Expand All @@ -1004,12 +1045,34 @@ public static V GetValueOrDefault<K, V>(this ImHashMap234<K, V> map, int hash, K
return default(V);
}

/// <summary>Looks up for the key using its hash code and returns found value or the default value if not found</summary>
/// <summary>Looks up for the key using its hash code and checking the key with `object.Equals` for equality,
/// returns found value or the default value if not found</summary>
[MethodImpl((MethodImplOptions)256)]
public static V GetValueOrDefault<K, V>(this ImHashMap234<K, V> map, K key) =>
map.GetValueOrDefault(key.GetHashCode(), key);

/// <summary>Looks up for the key using its hash code and returns the `true` and the found value or `false`</summary>
/// <summary>Looks up for the key using its hash code and checking the key with `object.ReferenceEquals` for equality,
/// returns found value or the default value if not found</summary>
[MethodImpl((MethodImplOptions)256)]
public static V GetValueOrDefaultReferenceEqual<K, V>(this ImHashMap234<K, V> map, int hash, K key) where K : class
{
var e = map.GetEntryOrDefault(hash);
if (e is ImHashMap234<K, V>.ValueEntry v)
{
if (e.Key == key)
return v.Value;
}
else if (e is ImHashMap234<K, V>.ConflictsEntry c)
{
foreach (var x in c.Conflicts)
if (x.Key == key)
return x.Value;
}
return default(V);
}

/// <summary>Looks up for the key using its hash code and checking the key with `object.Equals` for equality,
/// returns the `true` and the found value or `false`</summary>
[MethodImpl((MethodImplOptions)256)]
public static bool TryFind<K, V>(this ImHashMap234<K, V> map, int hash, K key, out V value)
{
Expand All @@ -1036,7 +1099,8 @@ public static bool TryFind<K, V>(this ImHashMap234<K, V> map, int hash, K key, o
return false;
}

/// <summary>Looks up for the key using its hash code and returns the `true` and the found value or `false`</summary>
/// <summary>Looks up for the key using its hash code and checking the key equality with the `ReferenceEquals`,
/// returns the `true` and the found value or `false`</summary>
[MethodImpl((MethodImplOptions)256)]
public static bool TryFindReferenceEqual<K, V>(this ImHashMap234<K, V> map, int hash, K key, out V value) where K : class
{
Expand Down Expand Up @@ -1064,7 +1128,6 @@ public static bool TryFindReferenceEqual<K, V>(this ImHashMap234<K, V> map, int
return false;
}


/// <summary>Looks up for the key using its hash code and returns the `true` and the found value or `false`</summary>
[MethodImpl((MethodImplOptions)256)]
public static bool TryFind<K, V>(this ImHashMap234<K, V> map, K key, out V value) =>
Expand Down
1 change: 1 addition & 0 deletions test/ImTools.UnitTests/Experimental.ImMap234Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ public void Adding_hash_and_keys_from_1_to_10_and_checking_the_tree_shape_on_eac
Assert.AreEqual("b", m.GetValueOrDefault(2));
Assert.AreEqual("a", m.GetValueOrDefault(1));
Assert.AreEqual(null, m.GetValueOrDefault(10));
Assert.AreSame(m, m.AddOrKeep(3, "aa").AddOrKeep(2, "bb").AddOrKeep(1, "cc"));

m = m.AddOrUpdate(7, "7");
Assert.AreEqual("7", m.GetValueOrDefault(7));
Expand Down

0 comments on commit f9fa692

Please sign in to comment.