Skip to content

Commit

Permalink
yay. using inline arrays for the 1st time
Browse files Browse the repository at this point in the history
  • Loading branch information
dadhi committed Jan 6, 2024
1 parent 7979dc3 commit 999976d
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 22 deletions.
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<!--Set to true to minimize number of target frameworks, to fasten the build :-) -->
<DevMode>true</DevMode>
<LangVersion>11</LangVersion>
<LangVersion>preview</LangVersion>

<Authors>Maksim Volkau</Authors>
<Copyright>Copyright © 2016-2023 Maksim Volkau</Copyright>
Expand Down
18 changes: 16 additions & 2 deletions playground/ImTools.Benchmarks/ImHashMapEnumerateBM.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
namespace ImTools.Playground;
namespace ImTools.Benchmarks;

using System;
using System.Collections.Generic;
using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Diagnosers;

/*
BenchmarkDotNet v0.13.12, Windows 11 (10.0.22631.2861/23H2/2023Update/SunValley3)
11th Gen Intel Core i7-1185G7 3.00GHz, 1 CPU, 8 logical and 4 physical cores
.NET SDK 8.0.100
[Host] : .NET 8.0.0 (8.0.23.53103), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
DefaultJob : .NET 8.0.0 (8.0.23.53103), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
| Method | ItemCount | Mean | Error | StdDev | Median | Ratio | RatioSD | Gen0 | Allocated | Alloc Ratio |
|--------------------------------- |---------- |---------:|----------:|----------:|---------:|------:|--------:|-------:|----------:|------------:|
| Enumerate_with_condition_stopper | 100 | 1.209 us | 0.0239 us | 0.0406 us | 1.203 us | 1.00 | 0.00 | - | - | NA |
| ForEach_with_condition_stopper | 100 | 1.334 us | 0.0265 us | 0.0669 us | 1.312 us | 1.12 | 0.08 | 0.0267 | 168 B | NA |
*/

[MemoryDiagnoser]
public class ImHashMapEnumerateBM
{
[Params(10)]
[Params(100)]
public int ItemCount;

[GlobalSetup]
Expand Down
6 changes: 3 additions & 3 deletions playground/ImTools.Benchmarks/Program.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
using BenchmarkDotNet.Running;
using Playground;

namespace ImTools.Benchmarks
{
class Program
{
static void Main()
{
BenchmarkRunner.Run<ImHashMapEnumerateBM>();

// new SIO.Program().Run();

//var x = new ImMapBenchmarks.Populate { Count = 10 };
Expand All @@ -20,9 +21,8 @@ static void Main()
// BenchmarkRunner.Run<ImMapBenchmarks.LookupMissing>();
// BenchmarkRunner.Run<ImMapBenchmarks.Enumerate>();


// BenchmarkRunner.Run<ImHashMapBenchmarks.Populate>();
BenchmarkRunner.Run<ImHashMapBenchmarks.Lookup>();
// BenchmarkRunner.Run<ImHashMapBenchmarks.Lookup>();
// BenchmarkRunner.Run<ImHashMapBenchmarks.Enumerate>();
// BenchmarkRunner.Run<ImHashMapBenchmarks.ToArray>();
// BenchmarkRunner.Run<ImHashMapBenchmarks.GetAndUpdate_vs_AddOrGetAndReplace>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<LangVersion />
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>

Expand Down
100 changes: 85 additions & 15 deletions src/ImTools/ImTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4146,6 +4146,7 @@ public sealed class MapParentStack
public MapParentStack() => _items = new object[DefaultInitialCapacity];

/// <summary>Pushes the item</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Put(object item, int index)
{
if (index >= _items.Length)
Expand Down Expand Up @@ -4368,6 +4369,76 @@ internal static void InsertInOrder<K, V>(int ph, ref ImHashMap<K, V>.Entry p,

private static readonly object _enumerationB3Tombstone = new object();

#if NET8_0_OR_GREATER
[System.Runtime.CompilerServices.InlineArray(8)]
internal struct Obj8
{
private object _element;
}

internal struct MapStack<K, V>
{
private Obj8 _mentries; // ImHashMap<K, V>.Entry
private Obj8 _branches; // ImHashMap<K, V>
private MapParentStack<K, V> _deeper;
private const byte _deeperStartsAtLevel = 8;

public void Put(ushort i, ImHashMap<K, V>.Entry e, ImHashMap<K, V> b)
{
if (i < 8)
{
_mentries[i] = e;
_branches[i] = b;
}
else
{
_deeper ??= new MapParentStack<K, V>(8);
_deeper.Put(i - _deeperStartsAtLevel, e, b);
}
}

public void Put(ushort i, ImHashMap<K, V>.Entry e, ImHashMap<K, V> b, ImHashMap<K, V>.Entry eNext, ImHashMap<K, V> bNext)
{
if (i < 7)
{
_mentries[i] = e;
_mentries[i + 1] = eNext;
_branches[i] = b;
_branches[i + 1] = bNext;
}
else if (i == 7)
{
_mentries[7] = e;
_branches[7] = e;
_deeper ??= new MapParentStack<K, V>(8);
_deeper.Put(0, eNext, bNext);
}
else
{
_deeper ??= new MapParentStack<K, V>(8);
i -= _deeperStartsAtLevel;
_deeper.Put(i, e, b);
_deeper.Put(i + 1, eNext, bNext);
}
}

public void Get(ushort i, ref ImHashMap<K, V>.Entry e, ref ImHashMap<K, V> b)
{
if (i < 8)
{
e = (ImHashMap<K, V>.Entry)_mentries[i];
b = (ImHashMap<K, V>)_branches[i];
}
else
{
Debug.Assert(_deeper != null, "Expecting the `deeper` parent stack created before accessing it here at level " + i);
ref var p = ref _deeper.Items[i - _deeperStartsAtLevel];
e = p.NextEntry;
b = p.NextBranch;
}
}
}
#else
internal struct MapStack<K, V>
{
ImHashMap<K, V>.Entry e0, e1, e2, e3, e4, e5, e6, e7;//, e8, e9, e10, e11, e12, e13, e14, e15;
Expand All @@ -4387,8 +4458,7 @@ public void Put(ushort i, ImHashMap<K, V>.Entry e, ImHashMap<K, V> b)
case 6: e6 = e; b6 = b; break;
case 7: e7 = e; b7 = b; break;
default:
if (_deeper == null)
_deeper = new MapParentStack<K, V>(8);
_deeper ??= new MapParentStack<K, V>(8);
_deeper.Put(i - _deeperStartsAtLevel, e, b);
break;
}
Expand All @@ -4407,11 +4477,11 @@ public void Put(ushort i, ImHashMap<K, V>.Entry e, ImHashMap<K, V> b, ImHashMap<
case 6: e6 = e; b6 = b; e7 = eNext; b7 = bNext; break;
case 7:
e7 = e; b7 = b;
if (_deeper == null) _deeper = new MapParentStack<K, V>(8);
_deeper ??= new MapParentStack<K, V>(8);
_deeper.Put(0, eNext, bNext);
break;
default:
if (_deeper == null) _deeper = new MapParentStack<K, V>(8);
_deeper ??= new MapParentStack<K, V>(8);
i -= _deeperStartsAtLevel;
_deeper.Put(i, e, b);
_deeper.Put(i + 1, eNext, bNext);
Expand Down Expand Up @@ -4439,6 +4509,7 @@ public void Get(ushort i, ref ImHashMap<K, V>.Entry e, ref ImHashMap<K, V> b)
}
}
}
#endif

/// <summary>Non-allocating enumerator</summary>
public struct Enumerable<V> : IEnumerable<VEntry<V>>, IEnumerable
Expand Down Expand Up @@ -4744,9 +4815,17 @@ public struct Enumerator<K, V> : IEnumerator<KVEntry<K, V>>, IDisposable, IEnume
{
internal ImHashMap<K, V> _map;
private short _state;
private short _conflictIndex;
private ushort _index;
private short _conflictIndex;
private MapStack<K, V> _ps;
private ImHashMap<K, V> _nextBranch;
private ImHashMap<K, V>.Branch2Plus _b21LeftWasEnumerated;
private ImHashMap<K, V>.Entry _a, _b, _c, _d, _e, _f, _g, _h, _hc;
internal KVEntry<K, V> _current;

/// <inheritdoc />
public KVEntry<K, V> Current => _current;
object IEnumerator.Current => _current;

internal void ReInit(ImHashMap<K, V> map)
{
Expand All @@ -4756,14 +4835,6 @@ internal void ReInit(ImHashMap<K, V> map)
_ps = default;
}

private ImHashMap<K, V> _nextBranch;
private ImHashMap<K, V>.Branch2Plus _b21LeftWasEnumerated;
private ImHashMap<K, V>.Entry _a, _b, _c, _d, _e, _f, _g, _h, _hc;
internal KVEntry<K, V> _current;
/// <inheritdoc />
public KVEntry<K, V> Current => _current;
object IEnumerator.Current => _current;

[MethodImpl((MethodImplOptions)256)]
private bool SetCurrentAndState(ImHashMap<K, V>.Entry e, short nextState, short prevState)
{
Expand Down Expand Up @@ -5290,8 +5361,7 @@ public static KVEntry<K, V> FindFirstOrDefault<K, V, S>(this ImHashMap<K, V> map
{
if (map is ImHashMap<K, V>.Branch2Base b2)
{
if (parents == null)
parents = new MapParentStack();
parents ??= new MapParentStack();
parents.Put(map, count++);
map = b2.Left;
continue;
Expand Down

0 comments on commit 999976d

Please sign in to comment.