From 6024d5d237e83a5e08daa6467229216af9765286 Mon Sep 17 00:00:00 2001 From: Atif Aziz Date: Thu, 20 Dec 2018 15:20:04 +0100 Subject: [PATCH] Add initial implementation of BindByIndex --- MoreLinq/BindByIndex.cs | 218 ++++++++++++++++++ MoreLinq/Extensions.g.cs | 54 +++++ .../PublicAPI/net6.0/PublicAPI.Unshipped.txt | 5 + .../PublicAPI/net8.0/PublicAPI.Unshipped.txt | 5 + .../PublicAPI/net9.0/PublicAPI.Unshipped.txt | 5 + .../netstandard2.0/PublicAPI.Unshipped.txt | 5 + .../netstandard2.1/PublicAPI.Unshipped.txt | 5 + 7 files changed, 297 insertions(+) create mode 100644 MoreLinq/BindByIndex.cs diff --git a/MoreLinq/BindByIndex.cs b/MoreLinq/BindByIndex.cs new file mode 100644 index 000000000..e707db6e1 --- /dev/null +++ b/MoreLinq/BindByIndex.cs @@ -0,0 +1,218 @@ +#region License and Terms +// MoreLINQ - Extensions to LINQ to Objects +// Copyright (c) 2018 Atif Aziz. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +namespace MoreLinq +{ + using System; + using System.Collections; + using System.Collections.Generic; + + static partial class MoreEnumerable + { + /// + /// TODO Complete documentation + /// + /// + /// Type of elements in sequence. + /// Type of result elements returned. + /// The source sequence. + /// The sequence of indices. + /// + /// TODO Complete documentation + /// + /// + /// TODO Complete documentation + /// + /// + /// TODO Complete documentation + /// + + public static IEnumerable + BindByIndex(this IEnumerable source, IEnumerable indices, + Func missingSelector, Func resultSelector) => + BindByIndex(source, indices, null, missingSelector, resultSelector); + + /// + /// TODO Complete documentation + /// + /// + /// Type of elements in sequence. + /// Type of result elements returned. + /// The source sequence. + /// The sequence of indices. + /// Size of look-back buffer. + /// + /// TODO Complete documentation + /// + /// + /// TODO Complete documentation + /// + /// + /// TODO Complete documentation + /// + + public static IEnumerable + BindByIndex(this IEnumerable source, IEnumerable indices, + int lookBackSize, + Func missingSelector, + Func resultSelector) => + BindByIndex(source, indices, (int?)lookBackSize, missingSelector, resultSelector); + + static IEnumerable + BindByIndex(IEnumerable source, IEnumerable indices, + int? lookBackSize, + Func missingSelector, + Func resultSelector) + { + if (source == null) throw new ArgumentNullException(nameof(source)); + if (indices == null) throw new ArgumentNullException(nameof(indices)); + if (lookBackSize < 0) throw new ArgumentOutOfRangeException(nameof(lookBackSize)); + if (missingSelector == null) throw new ArgumentNullException(nameof(missingSelector)); + if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); + + // TODO A version optimized for lists + + return _(lookBackSize switch + { + { } lbs and > 0 => new Queue(lbs, lbs), + 0 => null, + _ => new Queue() + }); + + IEnumerable _(Queue? queue) + { + using var rie = indices.GetEnumerator(); + if (!rie.MoveNext()) + yield break; + + while (rie.Current < 0) + { + yield return missingSelector(rie.Current); + if (!rie.MoveNext()) + yield break; + } + + var ri = rie.Current; + var si = 0; + + foreach (var item in source) + { + while (si == ri) + { + yield return resultSelector(item, si); + do + { + if (!rie.MoveNext()) + yield break; + ri = rie.Current; + if (ri < si) + { + if (queue is { } q && si - q.Count is var qi && ri >= qi) + yield return resultSelector(q[ri - qi], ri); + else + yield return missingSelector(ri); + } + } + while (ri < si); + } + + queue?.Enqueue(item); + si++; + } + + if (ri != si) + { + yield return missingSelector(ri); + while (rie.MoveNext()) + yield return missingSelector(rie.Current); + } + } + } + + /// + /// A queue implementation similar to + /// but which + /// supports a maximum count (exceeding which will cause an item to be + /// dequeued each to make space for a new one being queued) as well as + /// directly indexing into the queue to retrieve any one item. + /// + + sealed class Queue(int maxCount = 0, int capacity = 0) : IReadOnlyList + { + T[] items = capacity > 0 ? new T[capacity] : []; + int firstIndex; + readonly int maxCount = maxCount; + + int Capacity => this.items.Length; + public int Count { get; private set; } + + T IReadOnlyList.this[int index] => this[index]; + + public T this[int index] + { + get + { + if (index < 0 || index >= Count) + { + #pragma warning disable CA2201 // Do not raise reserved exception types + throw new IndexOutOfRangeException(); + #pragma warning restore CA2201 + } + + return Cell(index); + } + } + + ref T Cell(int index) => ref this.items[(this.firstIndex + index) % Capacity]; + + public void Enqueue(T item) + { + if (this.maxCount > 0 && Count == this.maxCount) + _ = Dequeue(); + + if (Count == Capacity) + { + var array = new T[Math.Max(4, Capacity * 2)]; + for (var i = 0; i < Count; i++) + array[i] = this[i]; + this.firstIndex = 0; + this.items = array; + } + + Cell(Count++) = item; + } + + public T Dequeue() + { + if (Count == 0) + throw new InvalidOperationException(); + var result = this[0]; + this.firstIndex++; + --Count; + return result; + } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + public IEnumerator GetEnumerator() + { + for (var i = 0; i < Count; i++) + yield return this[i]; + } + } + } +} diff --git a/MoreLinq/Extensions.g.cs b/MoreLinq/Extensions.g.cs index 52f76097c..f58837a88 100644 --- a/MoreLinq/Extensions.g.cs +++ b/MoreLinq/Extensions.g.cs @@ -716,6 +716,60 @@ public static IEnumerable Batch(this IEnumerableBindByIndex extension. + + [GeneratedCode("MoreLinq.ExtensionsGenerator", "1.0.0.0")] + public static partial class BindByIndexExtension + { + /// + /// TODO Complete documentation + /// + /// + /// Type of elements in sequence. + /// Type of result elements returned. + /// The source sequence. + /// The sequence of indices. + /// + /// TODO Complete documentation + /// + /// + /// TODO Complete documentation + /// + /// + /// TODO Complete documentation + /// + + public static IEnumerable + BindByIndex(this IEnumerable source, IEnumerable indices, + Func missingSelector, Func resultSelector) => MoreEnumerable. BindByIndex(source, indices, missingSelector, resultSelector); + + /// + /// TODO Complete documentation + /// + /// + /// Type of elements in sequence. + /// Type of result elements returned. + /// The source sequence. + /// The sequence of indices. + /// Size of look-back buffer. + /// + /// TODO Complete documentation + /// + /// + /// TODO Complete documentation + /// + /// + /// TODO Complete documentation + /// + + public static IEnumerable + BindByIndex(this IEnumerable source, IEnumerable indices, + int lookBackSize, + Func missingSelector, + Func resultSelector) => MoreEnumerable. BindByIndex(source, indices, lookBackSize, missingSelector, resultSelector); + + } + /// Cartesian extension. [GeneratedCode("MoreLinq.ExtensionsGenerator", "1.0.0.0")] diff --git a/MoreLinq/PublicAPI/net6.0/PublicAPI.Unshipped.txt b/MoreLinq/PublicAPI/net6.0/PublicAPI.Unshipped.txt index 7dc5c5811..c5f2f242d 100644 --- a/MoreLinq/PublicAPI/net6.0/PublicAPI.Unshipped.txt +++ b/MoreLinq/PublicAPI/net6.0/PublicAPI.Unshipped.txt @@ -1 +1,6 @@ #nullable enable +MoreLinq.Extensions.BindByIndexExtension +static MoreLinq.Extensions.BindByIndexExtension.BindByIndex(this System.Collections.Generic.IEnumerable! source, System.Collections.Generic.IEnumerable! indices, System.Func! missingSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.BindByIndexExtension.BindByIndex(this System.Collections.Generic.IEnumerable! source, System.Collections.Generic.IEnumerable! indices, int lookBackSize, System.Func! missingSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.BindByIndex(this System.Collections.Generic.IEnumerable! source, System.Collections.Generic.IEnumerable! indices, System.Func! missingSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.BindByIndex(this System.Collections.Generic.IEnumerable! source, System.Collections.Generic.IEnumerable! indices, int lookBackSize, System.Func! missingSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! diff --git a/MoreLinq/PublicAPI/net8.0/PublicAPI.Unshipped.txt b/MoreLinq/PublicAPI/net8.0/PublicAPI.Unshipped.txt index 7dc5c5811..c5f2f242d 100644 --- a/MoreLinq/PublicAPI/net8.0/PublicAPI.Unshipped.txt +++ b/MoreLinq/PublicAPI/net8.0/PublicAPI.Unshipped.txt @@ -1 +1,6 @@ #nullable enable +MoreLinq.Extensions.BindByIndexExtension +static MoreLinq.Extensions.BindByIndexExtension.BindByIndex(this System.Collections.Generic.IEnumerable! source, System.Collections.Generic.IEnumerable! indices, System.Func! missingSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.BindByIndexExtension.BindByIndex(this System.Collections.Generic.IEnumerable! source, System.Collections.Generic.IEnumerable! indices, int lookBackSize, System.Func! missingSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.BindByIndex(this System.Collections.Generic.IEnumerable! source, System.Collections.Generic.IEnumerable! indices, System.Func! missingSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.BindByIndex(this System.Collections.Generic.IEnumerable! source, System.Collections.Generic.IEnumerable! indices, int lookBackSize, System.Func! missingSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! diff --git a/MoreLinq/PublicAPI/net9.0/PublicAPI.Unshipped.txt b/MoreLinq/PublicAPI/net9.0/PublicAPI.Unshipped.txt index 7dc5c5811..c5f2f242d 100644 --- a/MoreLinq/PublicAPI/net9.0/PublicAPI.Unshipped.txt +++ b/MoreLinq/PublicAPI/net9.0/PublicAPI.Unshipped.txt @@ -1 +1,6 @@ #nullable enable +MoreLinq.Extensions.BindByIndexExtension +static MoreLinq.Extensions.BindByIndexExtension.BindByIndex(this System.Collections.Generic.IEnumerable! source, System.Collections.Generic.IEnumerable! indices, System.Func! missingSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.BindByIndexExtension.BindByIndex(this System.Collections.Generic.IEnumerable! source, System.Collections.Generic.IEnumerable! indices, int lookBackSize, System.Func! missingSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.BindByIndex(this System.Collections.Generic.IEnumerable! source, System.Collections.Generic.IEnumerable! indices, System.Func! missingSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.BindByIndex(this System.Collections.Generic.IEnumerable! source, System.Collections.Generic.IEnumerable! indices, int lookBackSize, System.Func! missingSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! diff --git a/MoreLinq/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt b/MoreLinq/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt index 7dc5c5811..c5f2f242d 100644 --- a/MoreLinq/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt +++ b/MoreLinq/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt @@ -1 +1,6 @@ #nullable enable +MoreLinq.Extensions.BindByIndexExtension +static MoreLinq.Extensions.BindByIndexExtension.BindByIndex(this System.Collections.Generic.IEnumerable! source, System.Collections.Generic.IEnumerable! indices, System.Func! missingSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.BindByIndexExtension.BindByIndex(this System.Collections.Generic.IEnumerable! source, System.Collections.Generic.IEnumerable! indices, int lookBackSize, System.Func! missingSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.BindByIndex(this System.Collections.Generic.IEnumerable! source, System.Collections.Generic.IEnumerable! indices, System.Func! missingSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.BindByIndex(this System.Collections.Generic.IEnumerable! source, System.Collections.Generic.IEnumerable! indices, int lookBackSize, System.Func! missingSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! diff --git a/MoreLinq/PublicAPI/netstandard2.1/PublicAPI.Unshipped.txt b/MoreLinq/PublicAPI/netstandard2.1/PublicAPI.Unshipped.txt index 7dc5c5811..c5f2f242d 100644 --- a/MoreLinq/PublicAPI/netstandard2.1/PublicAPI.Unshipped.txt +++ b/MoreLinq/PublicAPI/netstandard2.1/PublicAPI.Unshipped.txt @@ -1 +1,6 @@ #nullable enable +MoreLinq.Extensions.BindByIndexExtension +static MoreLinq.Extensions.BindByIndexExtension.BindByIndex(this System.Collections.Generic.IEnumerable! source, System.Collections.Generic.IEnumerable! indices, System.Func! missingSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.BindByIndexExtension.BindByIndex(this System.Collections.Generic.IEnumerable! source, System.Collections.Generic.IEnumerable! indices, int lookBackSize, System.Func! missingSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.BindByIndex(this System.Collections.Generic.IEnumerable! source, System.Collections.Generic.IEnumerable! indices, System.Func! missingSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.BindByIndex(this System.Collections.Generic.IEnumerable! source, System.Collections.Generic.IEnumerable! indices, int lookBackSize, System.Func! missingSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable!