Skip to content

Commit

Permalink
OptionalLinq: Refactor inner implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
andreise committed Dec 24, 2024
1 parent aa37917 commit d6a4986
Show file tree
Hide file tree
Showing 42 changed files with 757 additions and 653 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ public static Optional<TSource> ElementAtOrAbsent<TSource>(
this IEnumerable<TSource> source,
Index index)
=>
InnerElementAtOrAbsent(
InnerElementAtOrAbsent.Get(
source ?? throw new ArgumentNullException(nameof(source)),
index);

public static Optional<TSource> ElementAtOrAbsent<TSource>(
this IEnumerable<TSource> source,
int index)
=>
InnerElementAtOrAbsent(
InnerElementAtOrAbsent.Get(
source ?? throw new ArgumentNullException(nameof(source)),
index);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ partial class OptionalLinqExtensions
public static Optional<TSource> FirstOrAbsent<TSource>(
this IEnumerable<TSource> source)
=>
InnerFirstOrAbsent(
InnerFirstOrAbsent.Get(
source ?? throw new ArgumentNullException(nameof(source)));

public static Optional<TSource> FirstOrAbsent<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate)
=>
InnerFirstOrAbsent(
InnerFirstOrAbsent.Get(
source ?? throw new ArgumentNullException(nameof(source)),
predicate ?? throw new ArgumentNullException(nameof(predicate)));
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@ public static Optional<TValue> GetValueOrAbsent<TKey, TValue>(
this IEnumerable<KeyValuePair<TKey, TValue>> pairs,
TKey key)
=>
InnerGetValueOrAbsent(
InnerValueOrAbsent.Get(
pairs ?? throw new ArgumentNullException(nameof(pairs)),
key);

private const string NotIntendedMessage_TryGetValueOrAbsent
=
"This method is not intended for use. Call GetValueOrAbsent instead.";

[Obsolete(NotIntendedMessage_TryGetValueOrAbsent, error: true)]
[DoesNotReturn]
public static Optional<TValue> TryGetValueOrAbsent<TKey, TValue>(
this IEnumerable<KeyValuePair<TKey, TValue>> pairs,
TKey key)
=>
throw new NotImplementedException(NotIntendedMessage_TryGetValueOrAbsent);

private const string NotIntendedMessage_TryGetValueOrAbsent
=
$"This method is not intended for use. Call {nameof(GetValueOrAbsent)} instead.";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System.Collections.Generic;
using System.Runtime.CompilerServices;

namespace System.Linq;

partial class OptionalLinqExtensions
{
private static partial class InnerElementAtOrAbsent
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Optional<TSource> Get<TSource>(
IEnumerable<TSource> source,
Index index)
=>
source switch
{
IReadOnlyList<TSource> list
=>
InnerGet(list, index.GetOffset(list.Count)),

IList<TSource> list
=>
InnerGet(list, index.GetOffset(list.Count)),

_ => index.IsFromEnd is false
? InnerGet(source, index.Value)
: InnerGetFromEnd(source, index.Value)
};

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Optional<TSource> Get<TSource>(
IEnumerable<TSource> source,
int index)
=>
source switch
{
IReadOnlyList<TSource> list
=>
InnerGet(list, index),

IList<TSource> list
=>
InnerGet(list, index),

_ =>
InnerGet(source, index)
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System.Collections.Generic;
using System.Runtime.CompilerServices;

namespace System.Linq;

partial class OptionalLinqExtensions
{
partial class InnerElementAtOrAbsent
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Optional<TSource> InnerGet<TSource>(
IEnumerable<TSource> source,
int index)
{
if (index >= 0)
{
using var enumerator = source.GetEnumerator();

if (enumerator.MoveNext())
{
var countdownIndex = index;

do
{
if (countdownIndex == 0)
{
return new(enumerator.Current);
}

countdownIndex--;
}
while (enumerator.MoveNext());
}
}

return default;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System.Collections.Generic;
using System.Runtime.CompilerServices;

namespace System.Linq;

partial class OptionalLinqExtensions
{
partial class InnerElementAtOrAbsent
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Optional<TSource> InnerGetFromEnd<TSource>(
IEnumerable<TSource> source,
int indexFromEnd)
{
if (indexFromEnd > 0)
{
using var enumerator = source.GetEnumerator();

if (enumerator.MoveNext() is not true)
{
return default;
}

Queue<TSource> queue = new();
queue.Enqueue(enumerator.Current);

while (enumerator.MoveNext())
{
if (queue.Count == indexFromEnd)
{
_ = queue.Dequeue();
}

queue.Enqueue(enumerator.Current);
}

if (queue.Count == indexFromEnd)
{
return queue.Dequeue();
}
}

return default;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Collections.Generic;
using System.Runtime.CompilerServices;

namespace System.Linq;

partial class OptionalLinqExtensions
{
partial class InnerElementAtOrAbsent
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Optional<TSource> InnerGet<TSource>(
IList<TSource> source,
int index)
=>
index >= 0 && index < source.Count ? new(source[index]) : default;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Collections.Generic;
using System.Runtime.CompilerServices;

namespace System.Linq;

partial class OptionalLinqExtensions
{
partial class InnerElementAtOrAbsent
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Optional<TSource> InnerGet<TSource>(
IReadOnlyList<TSource> source,
int index)
=>
index >= 0 && index < source.Count ? new(source[index]) : default;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System.Collections.Generic;
using System.Runtime.CompilerServices;

namespace System.Linq;

partial class OptionalLinqExtensions
{
private static partial class InnerFirstOrAbsent
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Optional<TSource> Get<TSource>(
IEnumerable<TSource> source)
=>
source switch
{
IReadOnlyList<TSource> list
=>
InnerGet(list),

IList<TSource> list
=>
InnerGet(list),

_ =>
InnerGet(source)
};

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Optional<TSource> Get<TSource>(
IEnumerable<TSource> source,
Func<TSource, bool> predicate)
=>
source switch
{
IReadOnlyList<TSource> list
=>
InnerGet(list, predicate),

IList<TSource> list
=>
InnerGet(list, predicate),

_ =>
InnerGet(source, predicate)
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System.Collections.Generic;
using System.Runtime.CompilerServices;

namespace System.Linq;

partial class OptionalLinqExtensions
{
partial class InnerFirstOrAbsent
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Optional<TSource> InnerGet<TSource>(
IEnumerable<TSource> source)
{
using var enumerator = source.GetEnumerator();

return enumerator.MoveNext()
? new(enumerator.Current)
: default;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Optional<TSource> InnerGet<TSource>(
IEnumerable<TSource> source,
Func<TSource, bool> predicate)
{
foreach (var current in source)
{
if (predicate.Invoke(current))
{
return new(current);
}
}

return default;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System.Collections.Generic;
using System.Runtime.CompilerServices;

namespace System.Linq;

partial class OptionalLinqExtensions
{
partial class InnerFirstOrAbsent
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Optional<TSource> InnerGet<TSource>(
IList<TSource> source)
=>
source.Count > 0 ? new(source[0]) : default;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Optional<TSource> InnerGet<TSource>(
IList<TSource> source,
Func<TSource, bool> predicate)
{
for (var i = 0; i < source.Count; i++)
{
var current = source[i];

if (predicate.Invoke(current))
{
return new(current);
}
}

return default;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System.Collections.Generic;
using System.Runtime.CompilerServices;

namespace System.Linq;

partial class OptionalLinqExtensions
{
partial class InnerFirstOrAbsent
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Optional<TSource> InnerGet<TSource>(
IReadOnlyList<TSource> source)
=>
source.Count > 0 ? new(source[0]) : default;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Optional<TSource> InnerGet<TSource>(
IReadOnlyList<TSource> source,
Func<TSource, bool> predicate)
{
for (var i = 0; i < source.Count; i++)
{
var current = source[i];

if (predicate.Invoke(current))
{
return new(current);
}
}

return default;
}
}
}
Loading

0 comments on commit d6a4986

Please sign in to comment.