Skip to content

Commit 2065a98

Browse files
author
maximv
committed
experiments with the Enumerate and custom Enumerator
1 parent d45635b commit 2065a98

File tree

6 files changed

+154
-57
lines changed

6 files changed

+154
-57
lines changed

appveyor.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ for:
1919
- image: Visual Studio 2019
2020

2121
build_script:
22-
- build.bat
22+
- build_with_packaging.bat
2323

2424
artifacts:
2525
- path: .\.dist\packages\*.nupkg

build.bat

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,6 @@ if %ERRORLEVEL% neq 0 goto :error
2121
echo:
2222
echo:## Finished: TESTS
2323

24-
echo:
25-
echo:## Starting: SOURCE PACKAGING...
26-
echo:
27-
call BuildScripts\NugetPack.bat
28-
if %ERRORLEVEL% neq 0 goto :error
29-
echo:
30-
echo:## Finished: SOURCE PACKAGING
3124
echo:
3225
echo:## Finished: ALL ##
3326
echo:

build_no_packaging.bat renamed to build_with_packaging.bat

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ if %ERRORLEVEL% neq 0 goto :error
2121
echo:
2222
echo:## Finished: TESTS
2323

24+
echo:
25+
echo:## Starting: SOURCE PACKAGING...
26+
echo:
27+
call BuildScripts\NugetPack.bat
28+
if %ERRORLEVEL% neq 0 goto :error
29+
echo:
30+
echo:## Finished: SOURCE PACKAGING
2431
echo:
2532
echo:## Finished: ALL ##
2633
echo:

playground/ImTools.Benchmarks/ImHashMapBenchmarks.cs

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1444,20 +1444,19 @@ public class Enumerate
14441444
### Array instead of List
14451445
14461446
1447-
| Method | Count | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
1448-
|----------------------------------------- |------ |---------:|---------:|---------:|------:|--------:|-------:|------:|------:|----------:|
1449-
| V2_ImHashMap_AVL_EnumerateAndToArray | 10 | 649.9 ns | 29.18 ns | 84.19 ns | 1.00 | 0.00 | 0.1125 | - | - | 472 B |
1450-
| V3_ImHashMap_234Tree_EnumerateAndToArray | 10 | 871.5 ns | 17.01 ns | 18.90 ns | 1.41 | 0.10 | 0.1278 | - | - | 536 B |
1447+
| Method | Count | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
1448+
|----------------------------------------- |------ |---------:|--------:|--------:|------:|--------:|-------:|------:|------:|----------:|
1449+
| V2_ImHashMap_AVL_EnumerateAndToArray | 9 | 524.8 ns | 7.52 ns | 6.28 ns | 1.00 | 0.00 | 0.1087 | - | - | 456 B |
1450+
| V3_ImHashMap_234Tree_EnumerateAndToArray | 9 | 586.4 ns | 7.62 ns | 7.13 ns | 1.12 | 0.02 | 0.1163 | - | - | 488 B |
14511451
14521452
*/
1453-
[Params(10)]//, 5, 10, 100, 1_000)]// the 1000 does not add anything as the LookupKey stored higher in the tree, 1000)]
1453+
[Params(9)]//, 5, 10, 100, 1_000)]// the 1000 does not add anything as the LookupKey stored higher in the tree, 1000)]
14541454
public int Count;
14551455

14561456
[GlobalSetup]
14571457
public void Populate()
14581458
{
14591459
_map = AddOrUpdate();
1460-
_mapV1 = AddOrUpdate_v1();
14611460
_mapExp = Experimental_ImHashMap_AddOrUpdate();
14621461
_map234 = V3_ImHashMap_234Tree_AddOrUpdate();
14631462
_mapSlots = ImHashMapSlots_AddOrUpdate();
@@ -1476,7 +1475,7 @@ public ImHashMap<Type, string> AddOrUpdate()
14761475
foreach (var key in _keys.Take(Count))
14771476
map = map.AddOrUpdate(key, "a");
14781477

1479-
map = map.AddOrUpdate(typeof(ImHashMapBenchmarks), "!");
1478+
// map = map.AddOrUpdate(typeof(ImHashMapBenchmarks), "!");
14801479
return map;
14811480
}
14821481

@@ -1515,7 +1514,7 @@ public ImHashMap<Type, string>[] ImHashMapSlots_AddOrUpdate()
15151514
foreach (var key in _keys.Take(Count))
15161515
map = map.AddOrUpdate(key.GetHashCode(), key, "a");
15171516

1518-
return map.AddOrUpdate(typeof(ImHashMapBenchmarks).GetHashCode(), typeof(ImHashMapBenchmarks), "!");
1517+
return map;//.AddOrUpdate(typeof(ImHashMapBenchmarks).GetHashCode(), typeof(ImHashMapBenchmarks), "!");
15191518
}
15201519

15211520
private ImTools.Experimental.ImHashMap234<Type, string> _map234;
@@ -1527,7 +1526,7 @@ public ImTools.Experimental.ImHashMap234<Type, string> V3_ImHashMap_234Tree_AddO
15271526
foreach (var key in _keys.Take(Count))
15281527
map = map.AddOrUpdate(key.GetHashCode(), key, "a");
15291528

1530-
return map.AddOrUpdate(typeof(ImHashMapBenchmarks).GetHashCode(), typeof(ImHashMapBenchmarks), "!");
1529+
return map;//.AddOrUpdate(typeof(ImHashMapBenchmarks).GetHashCode(), typeof(ImHashMapBenchmarks), "!");
15311530
}
15321531

15331532
private ImHashMap<Type, string>[] _mapSlots;
@@ -1539,7 +1538,7 @@ public Dictionary<Type, string> Dict()
15391538
foreach (var key in _keys.Take(Count))
15401539
map.TryAdd(key, "a");
15411540

1542-
map.TryAdd(typeof(ImHashMapBenchmarks), "!");
1541+
// map.TryAdd(typeof(ImHashMapBenchmarks), "!");
15431542

15441543
return map;
15451544
}
@@ -1553,7 +1552,7 @@ public DictionarySlim<TypeVal, string> DictSlim()
15531552
foreach (var key in _keys.Take(Count))
15541553
dict.GetOrAddValueRef(key) = "a";
15551554

1556-
dict.GetOrAddValueRef(typeof(ImHashMapBenchmarks)) = "!";
1555+
// dict.GetOrAddValueRef(typeof(ImHashMapBenchmarks)) = "!";
15571556
return dict;
15581557
}
15591558

@@ -1566,7 +1565,7 @@ public ConcurrentDictionary<Type, string> ConcurrentDict()
15661565
foreach (var key in _keys.Take(Count))
15671566
map.TryAdd(key, "a");
15681567

1569-
map.TryAdd(typeof(ImHashMapBenchmarks), "!");
1568+
// map.TryAdd(typeof(ImHashMapBenchmarks), "!");
15701569
return map;
15711570
}
15721571

@@ -1578,7 +1577,7 @@ public ImmutableDictionary<Type, string> ImmutableDict()
15781577

15791578
foreach (var key in _keys.Take(Count))
15801579
builder.Add(key, "a");
1581-
builder.Add(typeof(ImHashMapBenchmarks), "!");
1580+
// builder.Add(typeof(ImHashMapBenchmarks), "!");
15821581
return builder.ToImmutable();
15831582
}
15841583

playground/ImTools.Benchmarks/Program.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ static void Main()
1818
//BenchmarkRunner.Run<ImMapBenchmarks.LookupMissing>();
1919
//BenchmarkRunner.Run<ImMapBenchmarks.Enumerate>();
2020

21-
BenchmarkRunner.Run<ImHashMapBenchmarks.Populate>();
21+
// BenchmarkRunner.Run<ImHashMapBenchmarks.Populate>();
2222
// BenchmarkRunner.Run<ImHashMapBenchmarks.Lookup>();
23-
// BenchmarkRunner.Run<ImHashMapBenchmarks.Enumerate>();
23+
BenchmarkRunner.Run<ImHashMapBenchmarks.Enumerate>();
2424

2525
// BenchmarkRunner.Run<ImHashMapBenchmarks_StringString.Populate>();
2626
// BenchmarkRunner.Run<ImHashMapBenchmarks_StringString.Lookup>();

src/ImTools/ImTools.ImHashMap234.cs

Lines changed: 132 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Runtime.CompilerServices;
77
using System.Text;
88
using System.Threading;
9+
using System.Collections;
910

1011
namespace ImTools.Experimental
1112
{
@@ -351,18 +352,59 @@ public override Entry GetEntryOrDefault(int hash) =>
351352
/// <inheritdoc />
352353
public override IEnumerable<ValueEntry> Enumerate()
353354
{
354-
if (Entry0 is ValueEntry v0)
355-
yield return v0;
356-
else foreach (var x in ((ConflictsEntry)Entry0).Conflicts)
357-
yield return x;
358-
if (Entry1 is ValueEntry v1)
359-
yield return v1;
360-
else foreach (var x in ((ConflictsEntry)Entry1).Conflicts)
361-
yield return x;
362-
if (Entry2 is ValueEntry v2)
363-
yield return v2;
364-
else foreach (var x in ((ConflictsEntry)Entry2).Conflicts)
365-
yield return x;
355+
return new Enumerable(this);
356+
357+
// if (Entry0 is ValueEntry v0)
358+
// yield return v0;
359+
// else foreach (var x in ((ConflictsEntry)Entry0).Conflicts)
360+
// yield return x;
361+
// if (Entry1 is ValueEntry v1)
362+
// yield return v1;
363+
// else foreach (var x in ((ConflictsEntry)Entry1).Conflicts)
364+
// yield return x;
365+
// if (Entry2 is ValueEntry v2)
366+
// yield return v2;
367+
// else foreach (var x in ((ConflictsEntry)Entry2).Conflicts)
368+
// yield return x;
369+
}
370+
371+
372+
private readonly struct Enumerable : IEnumerable<ValueEntry>
373+
{
374+
private readonly Leaf3 _l;
375+
public Enumerable(Leaf3 l) => _l = l;
376+
public Enumerator GetEnumerator() => new Enumerator(_l, 0);
377+
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
378+
IEnumerator<ValueEntry> IEnumerable<ValueEntry>.GetEnumerator() => GetEnumerator();
379+
}
380+
381+
private struct Enumerator : IEnumerator<ValueEntry>
382+
{
383+
private readonly Leaf3 _l;
384+
private byte _i;
385+
public Enumerator(Leaf3 l, byte i)
386+
{
387+
_l = l;
388+
_i = i;
389+
}
390+
391+
public ValueEntry Current
392+
{
393+
[MethodImpl((MethodImplOptions)256)]
394+
get
395+
{
396+
var i = _i;
397+
return (ValueEntry)(
398+
i == 1 ? _l.Entry0 :
399+
i == 2 ? _l.Entry1 :
400+
_l.Entry2);
401+
}
402+
}
403+
object IEnumerator.Current => Current;
404+
public bool MoveNext() => ++_i < 4;
405+
406+
public void Dispose() {}
407+
public void Reset() => _i = 0;
366408
}
367409

368410
/// <inheritdoc />
@@ -450,7 +492,6 @@ public override IEnumerable<ValueEntry> Enumerate()
450492
var e1 = l.Entry1;
451493
var e2 = l.Entry2;
452494

453-
// [2*, 3, 4]
454495
if (ph < e0.Hash)
455496
{
456497
if (p is ValueEntry v)
@@ -707,7 +748,7 @@ public override ImHashMap234<K, V> RemoveEntry(int hash, K key)
707748
}
708749

709750
/// <summary>Leaf with 5 entries</summary>
710-
public sealed class Leaf5 : ImHashMap234<K, V>
751+
public sealed class Leaf5 : ImHashMap234<K, V>, IEnumerable<ValueEntry>
711752
{
712753
/// <summary>Left entry</summary>
713754
public readonly Entry Entry0;
@@ -751,26 +792,75 @@ public override Entry GetEntryOrDefault(int hash) =>
751792
/// <inheritdoc />
752793
public override IEnumerable<ValueEntry> Enumerate()
753794
{
754-
if (Entry0 is ValueEntry v0)
755-
yield return v0;
756-
else foreach (var x in ((ConflictsEntry)Entry0).Conflicts)
757-
yield return x;
758-
if (Entry1 is ValueEntry v1)
759-
yield return v1;
760-
else foreach (var x in ((ConflictsEntry)Entry1).Conflicts)
761-
yield return x;
762-
if (Entry2 is ValueEntry v2)
763-
yield return v2;
764-
else foreach (var x in ((ConflictsEntry)Entry2).Conflicts)
765-
yield return x;
766-
if (Entry3 is ValueEntry v3)
767-
yield return v3;
768-
else foreach (var x in ((ConflictsEntry)Entry3).Conflicts)
769-
yield return x;
770-
if (Entry4 is ValueEntry v4)
771-
yield return v4;
772-
else foreach (var x in ((ConflictsEntry)Entry4).Conflicts)
773-
yield return x;
795+
return this;
796+
// if (Entry0 is ValueEntry v0)
797+
// yield return v0;
798+
// else foreach (var x in ((ConflictsEntry)Entry0).Conflicts)
799+
// yield return x;
800+
// if (Entry1 is ValueEntry v1)
801+
// yield return v1;
802+
// else foreach (var x in ((ConflictsEntry)Entry1).Conflicts)
803+
// yield return x;
804+
// if (Entry2 is ValueEntry v2)
805+
// yield return v2;
806+
// else foreach (var x in ((ConflictsEntry)Entry2).Conflicts)
807+
// yield return x;
808+
// if (Entry3 is ValueEntry v3)
809+
// yield return v3;
810+
// else foreach (var x in ((ConflictsEntry)Entry3).Conflicts)
811+
// yield return x;
812+
// if (Entry4 is ValueEntry v4)
813+
// yield return v4;
814+
// else foreach (var x in ((ConflictsEntry)Entry4).Conflicts)
815+
// yield return x;
816+
}
817+
818+
/// <summary>Returns the left-to-right enumerator</summary>
819+
public IEnumerator<ValueEntry> GetEnumerator() => new Enumerator(this);
820+
IEnumerator<ValueEntry> IEnumerable<ValueEntry>.GetEnumerator() => GetEnumerator();
821+
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
822+
823+
private struct Enumerator : IEnumerator<ValueEntry>
824+
{
825+
private readonly Leaf5 _m;
826+
private byte _i, _j;
827+
public Enumerator(Leaf5 m)
828+
{
829+
_m = m;
830+
_i = 0;
831+
_j = 0;
832+
Current = null;
833+
}
834+
835+
public ValueEntry Current { get; private set; }
836+
object IEnumerator.Current => Current;
837+
public bool MoveNext()
838+
{
839+
for (var i = _i; i < 5; ++_i)
840+
{
841+
var e = i == 0 ? _m.Entry0 : i == 1 ? _m.Entry1 : i == 2 ? _m.Entry2 : i == 3 ? _m.Entry3 : _m.Entry4;
842+
if (_j == 0 && e is ValueEntry v0)
843+
{
844+
Current = v0;
845+
++_i;
846+
return true;
847+
}
848+
849+
var ee = ((ConflictsEntry)e).Conflicts;
850+
if (_j < (uint)ee.Length)
851+
{
852+
Current = ee[_j++];
853+
return true;
854+
}
855+
856+
_j = 0;
857+
}
858+
859+
return false;
860+
}
861+
862+
public void Dispose() {}
863+
public void Reset() {}
774864
}
775865

776866
/// <inheritdoc />
@@ -2123,4 +2213,12 @@ public static void AddOrUpdate<K, V>(this ImHashMap234<K, V>[] parts, K key, V v
21232213
public static void RefAddOrUpdatePart<K, V>(ref ImHashMap234<K, V> part, int hash, K key, V value) =>
21242214
Ref.Swap(ref part, hash, key, value, (x, h, k, v) => x.AddOrUpdate(h, k, v));
21252215
}
2216+
2217+
/// <summary>Funny enumerable</summary>
2218+
public interface IEnumerable<out T, out TEnumerator> : IEnumerable<T>
2219+
where TEnumerator : IEnumerator<T>
2220+
{
2221+
/// <summary>Funny enumerator</summary>
2222+
new TEnumerator GetEnumerator();
2223+
}
21262224
}

0 commit comments

Comments
 (0)