Skip to content

Commit

Permalink
Optimize sequences and parallelism
Browse files Browse the repository at this point in the history
  • Loading branch information
fembina committed Nov 24, 2024
1 parent 3e5d066 commit b61ea8e
Show file tree
Hide file tree
Showing 8 changed files with 208 additions and 9 deletions.
19 changes: 16 additions & 3 deletions Sources/Falko.Talkie.Core/Concurrent/ParallelEnumeratorAdapter.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,31 @@
using System.Collections;
using System.Runtime.CompilerServices;

namespace Talkie.Concurrent;

internal sealed class ParallelEnumeratorAdapter<T>(IParallelEnumerator<T> parallelEnumerator) : IEnumerator<T>
[method: MethodImpl(MethodImplOptions.AggressiveInlining)]
internal struct ParallelEnumeratorAdapter<T>(IParallelEnumerator<T> parallelEnumerator) : IEnumerator<T>
{
private T? _current;

public T Current => _current!;
public T Current
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _current!;
}

object IEnumerator.Current => _current!;
object IEnumerator.Current
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _current!;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext() => parallelEnumerator.TryMoveNext(out _current);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Reset() => throw new NotSupportedException();

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Dispose() { }
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,18 @@ namespace Talkie.Sequences;

public partial class FrozenSequence<T>
{
public struct Enumerator : IEnumerator<T>
public struct HeapEnumerator : IEnumerator<T>
{
private readonly T[] _values;

private readonly int _valuesCount;

private int _currentIndex;

private T _currentValue;
private T _currentValue = default!;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal Enumerator(T[] values, int valuesCount)
internal HeapEnumerator(T[] values, int valuesCount)
{
_values = values;
_valuesCount = valuesCount;
Expand Down
69 changes: 69 additions & 0 deletions Sources/Falko.Talkie.Core/Sequences/FrozenSequence.Linq.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace Talkie.Sequences;

public partial class FrozenSequence<T>
{
public bool Any()
{
return _itemsCount > 0;
}

public T? FirstOrDefault()
{
return _itemsCount is 0
? default
: Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_items), 0);
}

public T First()
{
return _itemsCount is 0
? throw new InvalidOperationException()
: Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_items), 0);
}

public T? SingleOrDefault()
{
return _itemsCount is 1
? Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_items), 0)
: default;
}

public T Single()
{
return _itemsCount is 1
? Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_items), 0)
: throw new InvalidOperationException();
}

public T Last()
{
return _itemsCount is 0
? throw new InvalidOperationException()
: Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_items), _itemsCount - 1);
}

public T? LastOrDefault()
{
return _itemsCount is 0
? default
: Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_items), _itemsCount - 1);
}

public bool Contains(T value)
{
return Contains(value, EqualityComparer<T>.Default);
}

public bool Contains(T value, IEqualityComparer<T> comparer)
{
foreach (var item in this)
{
if (comparer.Equals(item, value)) return true;
}

return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System.Collections;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace Talkie.Sequences;

public partial class FrozenSequence<T>
{
public ref struct StackEnumerator : IEnumerator<T>
{
private readonly ref T _valuesReference;

private readonly int _valuesCount;

private int _currentIndex;

private T _currentValue = default!;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal StackEnumerator(T[] values, int valuesCount)
{
_valuesReference = ref MemoryMarshal.GetArrayDataReference(values);
_valuesCount = valuesCount;
}

public T Current
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _currentValue!;
}

object IEnumerator.Current
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _currentValue!;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext()
{
if (_currentIndex == _valuesCount) return false;

_currentValue = Unsafe.Add(ref _valuesReference, _currentIndex);

++_currentIndex;

return true;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Reset()
{
_currentIndex = 0;
_currentValue = default!;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Dispose() { }
}
}
9 changes: 6 additions & 3 deletions Sources/Falko.Talkie.Core/Sequences/FrozenSequence.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System.Collections;
using System.Diagnostics;
using Talkie.Concurrent;

namespace Talkie.Sequences;

[DebuggerDisplay("Count = {Count}")]
public partial class FrozenSequence<T> : IReadOnlySequence<T>
{
private readonly T[] _items;
Expand All @@ -11,17 +13,18 @@ public partial class FrozenSequence<T> : IReadOnlySequence<T>

public FrozenSequence(IEnumerable<T> values)
{
var list = new List<T>();
_items = values.ToArray();
_itemsCount = _items.Length;
}

public int Count => _itemsCount;

public Enumerator GetEnumerator() => new(_items, _itemsCount);
public StackEnumerator GetEnumerator() => new(_items, _itemsCount);

IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetEnumerator();
IEnumerator<T> IEnumerable<T>.GetEnumerator() => new HeapEnumerator(_items, _itemsCount);

IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => new HeapEnumerator(_items, _itemsCount);

public IParallelEnumerator<T> GetParallelEnumerator() => new ParallelEnumerator(_items, _itemsCount);

Expand Down
52 changes: 52 additions & 0 deletions Sources/Falko.Talkie.Core/Sequences/Sequence.Linq.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
namespace Talkie.Sequences;

public partial class Sequence<T>
{
public bool Any()
{
return _first is not null;
}

public T? FirstOrDefault()
{
return _first is null
? default
: _first.Value;
}

public T First()
{
return _first is null
? throw new InvalidOperationException()
: _first.Value;
}

public T Last()
{
return _last is null
? throw new InvalidOperationException()
: _last.Value;
}

public T? LastOrDefault()
{
return _last is null
? default
: _last.Value;
}

public bool Contains(T value)
{
return Contains(value, EqualityComparer<T>.Default);
}

public bool Contains(T value, IEqualityComparer<T> comparer)
{
for (var current = _first; current is not null; current = current.Next)
{
if (comparer.Equals(current.Value, value)) return true;
}

return false;
}
}
2 changes: 2 additions & 0 deletions Sources/Falko.Talkie.Core/Sequences/Sequence.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System.Collections;
using System.Diagnostics;
using Talkie.Concurrent;

namespace Talkie.Sequences;

[DebuggerDisplay("Count = {Count}")]
public partial class Sequence<T> : ISequence<T>
{
private Node? _first;
Expand Down

0 comments on commit b61ea8e

Please sign in to comment.