Skip to content

Commit fb05267

Browse files
Update project to v4.0.0 with various enhancements
Removed unused directives and files. Added and improved XML documentation across multiple files. Enhanced and added new methods in Extensions.cs. Modified Shuffle method to accept optional Random parameter. Simplified SequenceEqual method. Updated project and package versions in Open.Collections.csproj. Refactored ReadWriteSynchronizedCollectionWrapper. Added missing assertion in BasicCollectionTests.cs.
1 parent df9c947 commit fb05267

File tree

10 files changed

+91
-107
lines changed

10 files changed

+91
-107
lines changed

benchmarking/Benchmarks/SubsetBufferedBench.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using BenchmarkDotNet.Attributes;
22
using System;
3-
using System.Collections.Generic;
43
using System.Linq;
54

65
namespace Open.Collections.Benchmarks;

source/ArrayPoolSegment.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,16 @@ namespace Open.Collections;
1010
/// <typeparam name="T">The type of the elements in the array.</typeparam>
1111
public readonly struct ArrayPoolSegment<T> : IDisposable
1212
{
13+
/// <summary>
14+
/// The segment of the array.
15+
/// </summary>
1316
public readonly ArraySegment<T> Segment;
17+
18+
/// <summary>
19+
/// The <see cref="ArrayPool{T}"/> used to rent the array.
20+
/// </summary>
1421
public readonly ArrayPool<T>? Pool;
22+
1523
private readonly bool _clear;
1624

1725
/// <summary>

source/Extensions.Permutations.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
using Open.Disposable;
2-
using System;
1+
using System;
32
using System.Buffers;
43
using System.Collections.Generic;
54
using System.Diagnostics.Contracts;
65
using System.Linq;
76
using System.Numerics;
87
using System.Runtime.CompilerServices;
9-
using System.Xml.Linq;
108

119
namespace Open.Collections;
1210

source/Extensions.cs

Lines changed: 61 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -313,19 +313,35 @@ public static void ForEach<T>(this ISynchronizedCollection<T> target, Cancellati
313313
});
314314
}
315315

316-
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> target)
316+
/// <summary>
317+
/// Randomizes the order of the source.
318+
/// </summary>
319+
public static IEnumerable<T> Shuffle<T>(
320+
this IEnumerable<T> target, Random? rnd = null)
317321
{
318322
if (target is null)
319323
throw new ArgumentNullException(nameof(target));
320324
Contract.EndContractBlock();
321325

322-
var r = new Random();
326+
var r = rnd ?? new Random();
323327
return target.OrderBy(_ => r.Next());
324328
}
325329

326-
// Ensures an optimized means of acquiring Any();
327-
public static bool HasAny<T>(this IEnumerable<T> source) => source.HasAtLeast(1);
330+
/// <summary>
331+
/// Tests the count of the source to see if there's any items.
332+
/// </summary>
333+
/// <exception cref="ArgumentNullException">If the <paramref name="source"/> is null.</exception>
334+
/// <remarks>
335+
/// First checks the type to see if a count can be aquired directly. If not, it will iterate through the source to count the items.
336+
/// </remarks>
337+
public static bool HasAny<T>(this IEnumerable<T> source)
338+
=> source.HasAtLeast(1);
328339

340+
/// <summary>
341+
/// Tests the count of the source to see if there's at least the <paramref name="minimum"/> number of items.
342+
/// </summary>
343+
/// <exception cref="ArgumentOutOfRangeException">If the <paramref name="minimum"/> is less than 1.</exception>
344+
/// <inheritdoc cref="HasAny{T}(IEnumerable{T})"/>
329345
public static bool HasAtLeast<T>(this IEnumerable<T> source, int minimum)
330346
{
331347
if (source is null)
@@ -338,8 +354,12 @@ public static bool HasAtLeast<T>(this IEnumerable<T> source, int minimum)
338354
{
339355
case T[] array:
340356
return array.Length >= minimum;
357+
case IReadOnlyCollection<T> collection:
358+
return collection.Count >= minimum;
341359
case ICollection collection:
342360
return collection.Count >= minimum;
361+
case ICollection<T> collection:
362+
return collection.Count >= minimum;
343363
}
344364

345365
using IEnumerator<T>? e = source.GetEnumerator();
@@ -351,6 +371,9 @@ public static bool HasAtLeast<T>(this IEnumerable<T> source, int minimum)
351371
return false;
352372
}
353373

374+
/// <summary>
375+
/// Synchronizes enumerting by locking on the enumerator.
376+
/// </summary>
354377
public static bool ConcurrentTryMoveNext<T>(this IEnumerator<T> source, out T item)
355378
{
356379
// Always lock on next to prevent concurrency issues.
@@ -362,10 +385,14 @@ public static bool ConcurrentTryMoveNext<T>(this IEnumerator<T> source, out T it
362385
return true;
363386
}
364387
}
388+
365389
item = default!;
366390
return false;
367391
}
368392

393+
/// <summary>
394+
/// Syncronizes enumerting by locking on the enumerator and invokes the provided handlers depending on if .MoveNext() was true.
395+
/// </summary>
369396
public static bool ConcurrentMoveNext<T>(this IEnumerator<T> source, Action<T> trueHandler, Action? falseHandler = null)
370397
{
371398
// Always lock on next to prevent concurrency issues.
@@ -477,86 +504,19 @@ public static string ToConcatenatedString<T>(this IEnumerable<T> source, Func<T,
477504
return b.ToString();
478505
}
479506

480-
/// <summary>
481-
/// Shortcut to String.Join() using "," as a default value.
482-
/// </summary>
483-
public static string Join(this string[] array, char separator)
484-
{
485-
if (array is null)
486-
throw new ArgumentNullException(nameof(array));
487-
Contract.EndContractBlock();
488-
489-
return string.Join(separator + string.Empty, array);
490-
}
491-
492-
public static string Join(this string[] array, string separator = ",")
493-
{
494-
if (array is null)
495-
throw new ArgumentNullException(nameof(array));
496-
if (separator is null)
497-
throw new ArgumentNullException(nameof(separator));
498-
Contract.EndContractBlock();
499-
500-
return string.Join(separator, array);
501-
}
502-
503-
/// <summary>
504-
/// Concatenates a set of values into a single string using a character as a separator.
505-
/// </summary>
506-
public static string JoinToString<T>(this IEnumerable<T> source, char separator)
507-
{
508-
if (source is null) throw new ArgumentNullException(nameof(source));
509-
Contract.EndContractBlock();
510-
511-
var sb = new StringBuilder();
512-
using (IEnumerator<T>? enumerator = source.GetEnumerator())
513-
{
514-
if (enumerator.MoveNext())
515-
sb.Append(enumerator.Current);
516-
while (enumerator.MoveNext())
517-
sb.Append(separator).Append(enumerator.Current);
518-
}
519-
520-
return sb.ToString();
521-
}
522-
523-
/// <summary>
524-
/// Concatenates set of values into a single string using another string as a separator.
525-
/// </summary>
526-
public static string JoinToString<T>(this IEnumerable<T> source, string separator)
527-
{
528-
if (source is null) throw new ArgumentNullException(nameof(source));
529-
if (separator is null) throw new ArgumentNullException(nameof(separator));
530-
Contract.EndContractBlock();
531-
532-
var sb = new StringBuilder();
533-
using (IEnumerator<T>? enumerator = source.GetEnumerator())
534-
{
535-
if (enumerator.MoveNext())
536-
sb.Append(enumerator.Current);
537-
while (enumerator.MoveNext())
538-
sb.Append(separator).Append(enumerator.Current);
539-
}
540-
541-
return sb.ToString();
542-
}
543-
544507
/*public static T ValidateNotNull<T>(this T target)
545508
{
546509
547510
Contract.Assume(target is not null);
548511
return target;
549512
}*/
550513

551-
public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(this ParallelQuery<KeyValuePair<TKey, TValue>> source)
552-
where TKey : notnull
553-
{
554-
if (source is null) throw new ArgumentNullException(nameof(source));
555-
Contract.EndContractBlock();
556-
557-
return source.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
558-
}
559-
514+
#if NET9_0_OR_GREATER
515+
#else
516+
/// <summary>
517+
/// Returns a dictionary from the source key-value pairs.
518+
/// </summary>
519+
/// <exception cref="ArgumentNullException">If the <paramref name="source"/> is null.</exception>
560520
public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> source)
561521
where TKey : notnull
562522
{
@@ -565,7 +525,12 @@ public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(this IEnumerab
565525

566526
return source.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
567527
}
528+
#endif
568529

530+
/// <summary>
531+
/// Converts an enumerable to a sorted dictionary.
532+
/// </summary>
533+
/// <exception cref="ArgumentNullException">If the <paramref name="source"/> is null.</exception>
569534
public static SortedDictionary<TKey, TValue> ToSortedDictionary<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> source)
570535
where TKey : notnull
571536
{
@@ -579,6 +544,10 @@ public static SortedDictionary<TKey, TValue> ToSortedDictionary<TKey, TValue>(th
579544
return result;
580545
}
581546

547+
/// <summary>
548+
/// Converts an enumerable to a sorted dictionary.
549+
/// </summary>
550+
/// <exception cref="ArgumentNullException">If the <paramref name="source"/>, <paramref name="keySelector"/>, or <typeparamref name="TValue"/> are null.</exception>
582551
public static SortedDictionary<TKey, TValue> ToSortedDictionary<TSource, TKey, TValue>(this IEnumerable<TSource> source,
583552
Func<TSource, TKey> keySelector, Func<TSource, TValue> valueSelector)
584553
where TKey : notnull
@@ -595,6 +564,10 @@ public static SortedDictionary<TKey, TValue> ToSortedDictionary<TSource, TKey, T
595564
return result;
596565
}
597566

567+
/// <summary>
568+
/// Converts a grouping to a sorted dictionary.
569+
/// </summary>
570+
/// <exception cref="ArgumentNullException">If the <paramref name="source"/> is null.</exception>
598571
public static SortedDictionary<TKey, IEnumerable<TValue>> ToSortedDictionary<TKey, TValue>(this IEnumerable<IGrouping<TKey, TValue>> source)
599572
where TKey : notnull
600573
{
@@ -664,18 +637,8 @@ public static bool IsEquivalentTo<T>(this IEnumerable<T> source, IEnumerable<T>
664637
if (source is null || target is null)
665638
return false;
666639

667-
if (source is IReadOnlyCollection<T> sC && target is IReadOnlyCollection<T> tC && sC.Count != tC.Count)
668-
return false;
669-
670-
using IEnumerator<T>? enumSource = source.GetEnumerator();
671-
using IEnumerator<T>? enumTarget = target.GetEnumerator();
672-
while (enumSource.MoveNext() && enumTarget.MoveNext())
673-
{
674-
if (!enumSource.Current.Equals(enumTarget.Current))
675-
return false;
676-
}
677-
678-
return true;
640+
// Both are not null, okay go.
641+
return source.SequenceEqual(target);
679642
}
680643

681644
/// <summary>
@@ -843,6 +806,9 @@ private class OrderByInfo
843806
}
844807
#endregion
845808

809+
/// <summary>
810+
/// A nullable struct version of FirstOrDefault.
811+
/// </summary>
846812
public static T? NullableFirstOrDefault<T>(this IEnumerable<T> source)
847813
where T : struct
848814
{
@@ -854,6 +820,9 @@ private class OrderByInfo
854820
return null;
855821
}
856822

823+
/// <summary>
824+
/// Rotates through each enumerable and returns the next value until none are left.
825+
/// </summary>
857826
public static IEnumerable<T> Weave<T>(this IEnumerable<IEnumerable<T>> source)
858827
{
859828
LinkedList<IEnumerator<T>>? queue = null;
@@ -1067,6 +1036,9 @@ public static IEnumerator<T> Preflight<T>(
10671036
yield return source.Current;
10681037
}
10691038

1039+
/// <summary>
1040+
/// Executes an action when the begins <paramref name="source"/> enumeration.
1041+
/// </summary>
10701042
public static IEnumerable<T> BeforeGetEnumerator<T>(
10711043
this IEnumerable<T> source,
10721044
Action before)

source/Open.Collections.csproj

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
<PackageProjectUrl>https://github.com/Open-NET-Libraries/Open.Collections/</PackageProjectUrl>
1919
<RepositoryUrl>https://github.com/Open-NET-Libraries/Open.Collections/</RepositoryUrl>
2020
<RepositoryType>git</RepositoryType>
21-
<Version>3.2.0</Version>
21+
<Version>4.0.0</Version>
2222
<PackageReleaseNotes></PackageReleaseNotes>
2323
<PackageLicenseExpression>MIT</PackageLicenseExpression>
2424
<PublishRepositoryUrl>true</PublishRepositoryUrl>
@@ -42,16 +42,14 @@
4242
<Pack>True</Pack>
4343
<PackagePath>\</PackagePath>
4444
</None>
45-
<None Include="Extensions.ConcurrentBag.cs" />
46-
<None Include="NonGeneric\Extensions.Synchronized.cs" />
4745
<None Include="logo.png">
4846
<Pack>True</Pack>
4947
<PackagePath></PackagePath>
5048
</None>
5149
</ItemGroup>
5250

5351
<ItemGroup>
54-
<PackageReference Include="Open.Text" Version="8.1.0" />
52+
<PackageReference Include="Open.Text" Version="8.2.1" />
5553
<PackageReference Include="Open.Threading" Version="3.0.3" />
5654
<PackageReference Include="System.Collections.Immutable" Version="9.0.0" />
5755
</ItemGroup>

source/SortDirection.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
namespace Open.Collections;
22

3+
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
34
public enum SortDirection : sbyte
45
{
56
Ascending = +1,
67
Descending = -1
78
}
9+
#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member

source/Subsets.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77

88
namespace Open.Collections;
99

10+
/// <summary>
11+
/// Provides methods for generating subsets of a set.
12+
/// </summary>
1013
public static class Subsets
1114
{
1215
internal static IEnumerable<int[]> IndexesInternal(int sourceLength, int subsetLength, int[] buffer)

source/Synchronized/ReadWriteSynchronizedCollectionWrapper.cs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,19 @@
88

99
namespace Open.Collections.Synchronized;
1010

11-
public class ReadWriteSynchronizedCollectionWrapper<T, TCollection>
12-
: CollectionWrapper<T, TCollection>, ISynchronizedCollectionWrapper<T, TCollection>
11+
/// <summary>
12+
/// A disposable read-write synchronized wrapper for a collection.
13+
/// </summary>
14+
public class ReadWriteSynchronizedCollectionWrapper<T, TCollection>(
15+
TCollection source, bool owner = false)
16+
: CollectionWrapper<T, TCollection>(source, owner), ISynchronizedCollectionWrapper<T, TCollection>
1317
where TCollection : class, ICollection<T>
1418
{
19+
/// <summary>
20+
/// The <see cref="ReaderWriterLockSlim"/> used for synchronization.
21+
/// </summary>
1522
protected ReaderWriterLockSlim RWLock = new(LockRecursionPolicy.SupportsRecursion); // Support recursion for read -> write locks.
1623

17-
protected ReadWriteSynchronizedCollectionWrapper(TCollection source, bool owner = false)
18-
: base(source, owner)
19-
{
20-
}
21-
2224
#region Implementation of ICollection<T>
2325

2426
/// <inheritdoc />
@@ -118,10 +120,12 @@ public override Span<T> CopyTo(Span<T> span)
118120
#endregion
119121

120122
#region Dispose
121-
protected override void OnBeforeDispose() =>
123+
/// <inheritdoc />
124+
protected override void OnBeforeDispose()
122125
// Give everything else a chance to finish up.
123-
RWLock.TryWrite(1000, () => { });
126+
=> RWLock.TryWrite(1000, () => { });
124127

128+
/// <inheritdoc />
125129
protected override void OnDispose()
126130
{
127131
RWLock.Dispose();

testing/Open.Collections.Tests/BasicCollectionTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ public void Contains()
131131
Collection.Add(3);
132132
search = 2;
133133
}
134+
134135
Collection.Contains(search).Should().BeTrue();
135136

136137
if (Collection is not ISynchronizedCollectionWrapper<int, ICollection<int>> c) return;

testing/Open.Collections.Tests/PermutorTests.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Linq;
4-
using System.Numerics;
54
using FluentAssertions;
65
using Xunit;
76

0 commit comments

Comments
 (0)