Skip to content

Commit 6024d5d

Browse files
committed
Add initial implementation of BindByIndex
1 parent 9f6dc48 commit 6024d5d

File tree

7 files changed

+297
-0
lines changed

7 files changed

+297
-0
lines changed

MoreLinq/BindByIndex.cs

+218
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
#region License and Terms
2+
// MoreLINQ - Extensions to LINQ to Objects
3+
// Copyright (c) 2018 Atif Aziz. All rights reserved.
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
#endregion
17+
18+
namespace MoreLinq
19+
{
20+
using System;
21+
using System.Collections;
22+
using System.Collections.Generic;
23+
24+
static partial class MoreEnumerable
25+
{
26+
/// <summary>
27+
/// TODO Complete documentation
28+
/// </summary>
29+
/// <typeparam name="T">
30+
/// Type of elements in <paramref name="source"/> sequence.</typeparam>
31+
/// <typeparam name="TResult">Type of result elements returned.</typeparam>
32+
/// <param name="source">The source sequence.</param>
33+
/// <param name="indices">The sequence of indices.</param>
34+
/// <param name="missingSelector">
35+
/// TODO Complete documentation
36+
/// </param>
37+
/// <param name="resultSelector">
38+
/// TODO Complete documentation
39+
/// </param>
40+
/// <returns>
41+
/// TODO Complete documentation
42+
/// </returns>
43+
44+
public static IEnumerable<TResult>
45+
BindByIndex<T, TResult>(this IEnumerable<T> source, IEnumerable<int> indices,
46+
Func<int, TResult> missingSelector, Func<T, int, TResult> resultSelector) =>
47+
BindByIndex(source, indices, null, missingSelector, resultSelector);
48+
49+
/// <summary>
50+
/// TODO Complete documentation
51+
/// </summary>
52+
/// <typeparam name="T">
53+
/// Type of elements in <paramref name="source"/> sequence.</typeparam>
54+
/// <typeparam name="TResult">Type of result elements returned.</typeparam>
55+
/// <param name="source">The source sequence.</param>
56+
/// <param name="indices">The sequence of indices.</param>
57+
/// <param name="lookBackSize">Size of look-back buffer.</param>
58+
/// <param name="missingSelector">
59+
/// TODO Complete documentation
60+
/// </param>
61+
/// <param name="resultSelector">
62+
/// TODO Complete documentation
63+
/// </param>
64+
/// <returns>
65+
/// TODO Complete documentation
66+
/// </returns>
67+
68+
public static IEnumerable<TResult>
69+
BindByIndex<T, TResult>(this IEnumerable<T> source, IEnumerable<int> indices,
70+
int lookBackSize,
71+
Func<int, TResult> missingSelector,
72+
Func<T, int, TResult> resultSelector) =>
73+
BindByIndex(source, indices, (int?)lookBackSize, missingSelector, resultSelector);
74+
75+
static IEnumerable<TResult>
76+
BindByIndex<T, TResult>(IEnumerable<T> source, IEnumerable<int> indices,
77+
int? lookBackSize,
78+
Func<int, TResult> missingSelector,
79+
Func<T, int, TResult> resultSelector)
80+
{
81+
if (source == null) throw new ArgumentNullException(nameof(source));
82+
if (indices == null) throw new ArgumentNullException(nameof(indices));
83+
if (lookBackSize < 0) throw new ArgumentOutOfRangeException(nameof(lookBackSize));
84+
if (missingSelector == null) throw new ArgumentNullException(nameof(missingSelector));
85+
if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));
86+
87+
// TODO A version optimized for lists
88+
89+
return _(lookBackSize switch
90+
{
91+
{ } lbs and > 0 => new Queue<T>(lbs, lbs),
92+
0 => null,
93+
_ => new Queue<T>()
94+
});
95+
96+
IEnumerable<TResult> _(Queue<T>? queue)
97+
{
98+
using var rie = indices.GetEnumerator();
99+
if (!rie.MoveNext())
100+
yield break;
101+
102+
while (rie.Current < 0)
103+
{
104+
yield return missingSelector(rie.Current);
105+
if (!rie.MoveNext())
106+
yield break;
107+
}
108+
109+
var ri = rie.Current;
110+
var si = 0;
111+
112+
foreach (var item in source)
113+
{
114+
while (si == ri)
115+
{
116+
yield return resultSelector(item, si);
117+
do
118+
{
119+
if (!rie.MoveNext())
120+
yield break;
121+
ri = rie.Current;
122+
if (ri < si)
123+
{
124+
if (queue is { } q && si - q.Count is var qi && ri >= qi)
125+
yield return resultSelector(q[ri - qi], ri);
126+
else
127+
yield return missingSelector(ri);
128+
}
129+
}
130+
while (ri < si);
131+
}
132+
133+
queue?.Enqueue(item);
134+
si++;
135+
}
136+
137+
if (ri != si)
138+
{
139+
yield return missingSelector(ri);
140+
while (rie.MoveNext())
141+
yield return missingSelector(rie.Current);
142+
}
143+
}
144+
}
145+
146+
/// <summary>
147+
/// A queue implementation similar to
148+
/// <see cref="System.Collections.Generic.Queue{T}"/> but which
149+
/// supports a maximum count (exceeding which will cause an item to be
150+
/// dequeued each to make space for a new one being queued) as well as
151+
/// directly indexing into the queue to retrieve any one item.
152+
/// </summary>
153+
154+
sealed class Queue<T>(int maxCount = 0, int capacity = 0) : IReadOnlyList<T>
155+
{
156+
T[] items = capacity > 0 ? new T[capacity] : [];
157+
int firstIndex;
158+
readonly int maxCount = maxCount;
159+
160+
int Capacity => this.items.Length;
161+
public int Count { get; private set; }
162+
163+
T IReadOnlyList<T>.this[int index] => this[index];
164+
165+
public T this[int index]
166+
{
167+
get
168+
{
169+
if (index < 0 || index >= Count)
170+
{
171+
#pragma warning disable CA2201 // Do not raise reserved exception types
172+
throw new IndexOutOfRangeException();
173+
#pragma warning restore CA2201
174+
}
175+
176+
return Cell(index);
177+
}
178+
}
179+
180+
ref T Cell(int index) => ref this.items[(this.firstIndex + index) % Capacity];
181+
182+
public void Enqueue(T item)
183+
{
184+
if (this.maxCount > 0 && Count == this.maxCount)
185+
_ = Dequeue();
186+
187+
if (Count == Capacity)
188+
{
189+
var array = new T[Math.Max(4, Capacity * 2)];
190+
for (var i = 0; i < Count; i++)
191+
array[i] = this[i];
192+
this.firstIndex = 0;
193+
this.items = array;
194+
}
195+
196+
Cell(Count++) = item;
197+
}
198+
199+
public T Dequeue()
200+
{
201+
if (Count == 0)
202+
throw new InvalidOperationException();
203+
var result = this[0];
204+
this.firstIndex++;
205+
--Count;
206+
return result;
207+
}
208+
209+
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
210+
211+
public IEnumerator<T> GetEnumerator()
212+
{
213+
for (var i = 0; i < Count; i++)
214+
yield return this[i];
215+
}
216+
}
217+
}
218+
}

MoreLinq/Extensions.g.cs

+54
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,60 @@ public static IEnumerable<TResult> Batch<TSource, TResult>(this IEnumerable<TSou
716716

717717
}
718718

719+
/// <summary><c>BindByIndex</c> extension.</summary>
720+
721+
[GeneratedCode("MoreLinq.ExtensionsGenerator", "1.0.0.0")]
722+
public static partial class BindByIndexExtension
723+
{
724+
/// <summary>
725+
/// TODO Complete documentation
726+
/// </summary>
727+
/// <typeparam name="T">
728+
/// Type of elements in <paramref name="source"/> sequence.</typeparam>
729+
/// <typeparam name="TResult">Type of result elements returned.</typeparam>
730+
/// <param name="source">The source sequence.</param>
731+
/// <param name="indices">The sequence of indices.</param>
732+
/// <param name="missingSelector">
733+
/// TODO Complete documentation
734+
/// </param>
735+
/// <param name="resultSelector">
736+
/// TODO Complete documentation
737+
/// </param>
738+
/// <returns>
739+
/// TODO Complete documentation
740+
/// </returns>
741+
742+
public static IEnumerable<TResult>
743+
BindByIndex<T, TResult>(this IEnumerable<T> source, IEnumerable<int> indices,
744+
Func<int, TResult> missingSelector, Func<T, int, TResult> resultSelector) => MoreEnumerable. BindByIndex(source, indices, missingSelector, resultSelector);
745+
746+
/// <summary>
747+
/// TODO Complete documentation
748+
/// </summary>
749+
/// <typeparam name="T">
750+
/// Type of elements in <paramref name="source"/> sequence.</typeparam>
751+
/// <typeparam name="TResult">Type of result elements returned.</typeparam>
752+
/// <param name="source">The source sequence.</param>
753+
/// <param name="indices">The sequence of indices.</param>
754+
/// <param name="lookBackSize">Size of look-back buffer.</param>
755+
/// <param name="missingSelector">
756+
/// TODO Complete documentation
757+
/// </param>
758+
/// <param name="resultSelector">
759+
/// TODO Complete documentation
760+
/// </param>
761+
/// <returns>
762+
/// TODO Complete documentation
763+
/// </returns>
764+
765+
public static IEnumerable<TResult>
766+
BindByIndex<T, TResult>(this IEnumerable<T> source, IEnumerable<int> indices,
767+
int lookBackSize,
768+
Func<int, TResult> missingSelector,
769+
Func<T, int, TResult> resultSelector) => MoreEnumerable. BindByIndex(source, indices, lookBackSize, missingSelector, resultSelector);
770+
771+
}
772+
719773
/// <summary><c>Cartesian</c> extension.</summary>
720774

721775
[GeneratedCode("MoreLinq.ExtensionsGenerator", "1.0.0.0")]
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
11
#nullable enable
2+
MoreLinq.Extensions.BindByIndexExtension
3+
static MoreLinq.Extensions.BindByIndexExtension.BindByIndex<T, TResult>(this System.Collections.Generic.IEnumerable<T>! source, System.Collections.Generic.IEnumerable<int>! indices, System.Func<int, TResult>! missingSelector, System.Func<T, int, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!
4+
static MoreLinq.Extensions.BindByIndexExtension.BindByIndex<T, TResult>(this System.Collections.Generic.IEnumerable<T>! source, System.Collections.Generic.IEnumerable<int>! indices, int lookBackSize, System.Func<int, TResult>! missingSelector, System.Func<T, int, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!
5+
static MoreLinq.MoreEnumerable.BindByIndex<T, TResult>(this System.Collections.Generic.IEnumerable<T>! source, System.Collections.Generic.IEnumerable<int>! indices, System.Func<int, TResult>! missingSelector, System.Func<T, int, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!
6+
static MoreLinq.MoreEnumerable.BindByIndex<T, TResult>(this System.Collections.Generic.IEnumerable<T>! source, System.Collections.Generic.IEnumerable<int>! indices, int lookBackSize, System.Func<int, TResult>! missingSelector, System.Func<T, int, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
11
#nullable enable
2+
MoreLinq.Extensions.BindByIndexExtension
3+
static MoreLinq.Extensions.BindByIndexExtension.BindByIndex<T, TResult>(this System.Collections.Generic.IEnumerable<T>! source, System.Collections.Generic.IEnumerable<int>! indices, System.Func<int, TResult>! missingSelector, System.Func<T, int, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!
4+
static MoreLinq.Extensions.BindByIndexExtension.BindByIndex<T, TResult>(this System.Collections.Generic.IEnumerable<T>! source, System.Collections.Generic.IEnumerable<int>! indices, int lookBackSize, System.Func<int, TResult>! missingSelector, System.Func<T, int, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!
5+
static MoreLinq.MoreEnumerable.BindByIndex<T, TResult>(this System.Collections.Generic.IEnumerable<T>! source, System.Collections.Generic.IEnumerable<int>! indices, System.Func<int, TResult>! missingSelector, System.Func<T, int, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!
6+
static MoreLinq.MoreEnumerable.BindByIndex<T, TResult>(this System.Collections.Generic.IEnumerable<T>! source, System.Collections.Generic.IEnumerable<int>! indices, int lookBackSize, System.Func<int, TResult>! missingSelector, System.Func<T, int, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
11
#nullable enable
2+
MoreLinq.Extensions.BindByIndexExtension
3+
static MoreLinq.Extensions.BindByIndexExtension.BindByIndex<T, TResult>(this System.Collections.Generic.IEnumerable<T>! source, System.Collections.Generic.IEnumerable<int>! indices, System.Func<int, TResult>! missingSelector, System.Func<T, int, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!
4+
static MoreLinq.Extensions.BindByIndexExtension.BindByIndex<T, TResult>(this System.Collections.Generic.IEnumerable<T>! source, System.Collections.Generic.IEnumerable<int>! indices, int lookBackSize, System.Func<int, TResult>! missingSelector, System.Func<T, int, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!
5+
static MoreLinq.MoreEnumerable.BindByIndex<T, TResult>(this System.Collections.Generic.IEnumerable<T>! source, System.Collections.Generic.IEnumerable<int>! indices, System.Func<int, TResult>! missingSelector, System.Func<T, int, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!
6+
static MoreLinq.MoreEnumerable.BindByIndex<T, TResult>(this System.Collections.Generic.IEnumerable<T>! source, System.Collections.Generic.IEnumerable<int>! indices, int lookBackSize, System.Func<int, TResult>! missingSelector, System.Func<T, int, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
11
#nullable enable
2+
MoreLinq.Extensions.BindByIndexExtension
3+
static MoreLinq.Extensions.BindByIndexExtension.BindByIndex<T, TResult>(this System.Collections.Generic.IEnumerable<T>! source, System.Collections.Generic.IEnumerable<int>! indices, System.Func<int, TResult>! missingSelector, System.Func<T, int, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!
4+
static MoreLinq.Extensions.BindByIndexExtension.BindByIndex<T, TResult>(this System.Collections.Generic.IEnumerable<T>! source, System.Collections.Generic.IEnumerable<int>! indices, int lookBackSize, System.Func<int, TResult>! missingSelector, System.Func<T, int, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!
5+
static MoreLinq.MoreEnumerable.BindByIndex<T, TResult>(this System.Collections.Generic.IEnumerable<T>! source, System.Collections.Generic.IEnumerable<int>! indices, System.Func<int, TResult>! missingSelector, System.Func<T, int, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!
6+
static MoreLinq.MoreEnumerable.BindByIndex<T, TResult>(this System.Collections.Generic.IEnumerable<T>! source, System.Collections.Generic.IEnumerable<int>! indices, int lookBackSize, System.Func<int, TResult>! missingSelector, System.Func<T, int, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
11
#nullable enable
2+
MoreLinq.Extensions.BindByIndexExtension
3+
static MoreLinq.Extensions.BindByIndexExtension.BindByIndex<T, TResult>(this System.Collections.Generic.IEnumerable<T>! source, System.Collections.Generic.IEnumerable<int>! indices, System.Func<int, TResult>! missingSelector, System.Func<T, int, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!
4+
static MoreLinq.Extensions.BindByIndexExtension.BindByIndex<T, TResult>(this System.Collections.Generic.IEnumerable<T>! source, System.Collections.Generic.IEnumerable<int>! indices, int lookBackSize, System.Func<int, TResult>! missingSelector, System.Func<T, int, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!
5+
static MoreLinq.MoreEnumerable.BindByIndex<T, TResult>(this System.Collections.Generic.IEnumerable<T>! source, System.Collections.Generic.IEnumerable<int>! indices, System.Func<int, TResult>! missingSelector, System.Func<T, int, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!
6+
static MoreLinq.MoreEnumerable.BindByIndex<T, TResult>(this System.Collections.Generic.IEnumerable<T>! source, System.Collections.Generic.IEnumerable<int>! indices, int lookBackSize, System.Func<int, TResult>! missingSelector, System.Func<T, int, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!

0 commit comments

Comments
 (0)