Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace null-forgiving operator uses with debug assertions #890

Merged
merged 4 commits into from
Nov 16, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions MoreLinq/Debug.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#region License and Terms
// MoreLINQ - Extensions to LINQ to Objects
// Copyright (c) 2022 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.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;

static class Debug
{
[Conditional("DEBUG")]
public static void Assert([DoesNotReturnIf(false)] bool condition,
[CallerArgumentExpression(nameof(condition))] string? message = null) =>
System.Diagnostics.Debug.Assert(condition);
}
}
4 changes: 2 additions & 2 deletions MoreLinq/Experimental/Await.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ namespace MoreLinq.Experimental
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.ExceptionServices;
using System.Threading;
Expand Down Expand Up @@ -538,7 +537,8 @@ void PostNotice(Notice notice,

if (kind == Notice.Error)
{
error!.Throw();
Debug.Assert(error is not null);
error.Throw();
}

if (kind == Notice.End)
Expand Down
3 changes: 2 additions & 1 deletion MoreLinq/Experimental/Memoize.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ public IEnumerator<T> GetEnumerator()
{
if (index == _errorIndex)
{
_error!.Throw();
Debug.Assert(_error is not null);
_error.Throw();
}

if (_sourceEnumerator == null)
Expand Down
25 changes: 20 additions & 5 deletions MoreLinq/FallbackIfEmpty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ namespace MoreLinq
{
using System;
using System.Collections.Generic;
using System.Diagnostics;

static partial class MoreEnumerable
{
Expand Down Expand Up @@ -190,10 +189,26 @@ IEnumerable<T> FallbackOnArgs()
{
Debug.Assert(count is >= 1 and <= 4);

yield return fallback1!;
if (count > 1) yield return fallback2!;
if (count > 2) yield return fallback3!;
if (count > 3) yield return fallback4!;
Debug.Assert(fallback1 is not null);
yield return fallback1;

if (count > 1)
{
Debug.Assert(fallback2 is not null);
yield return fallback2;
}

if (count > 2)
{
Debug.Assert(fallback3 is not null);
yield return fallback3;
}

if (count > 3)
{
Debug.Assert(fallback4 is not null);
yield return fallback4;
}
}
}
}
Expand Down
71 changes: 52 additions & 19 deletions MoreLinq/Fold.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,26 +67,59 @@ static TResult FoldImpl<T, TResult>(IEnumerable<T> source, int count,
foreach (var e in AssertCountImpl(source.Index(), count, OnFolderSourceSizeErrorSelector))
elements[e.Key] = e.Value;

return count switch
switch (count)
{
1 => folder1 !(elements[0]),
2 => folder2 !(elements[0], elements[1]),
3 => folder3 !(elements[0], elements[1], elements[2]),
4 => folder4 !(elements[0], elements[1], elements[2], elements[3]),
5 => folder5 !(elements[0], elements[1], elements[2], elements[3], elements[4]),
6 => folder6 !(elements[0], elements[1], elements[2], elements[3], elements[4], elements[5]),
7 => folder7 !(elements[0], elements[1], elements[2], elements[3], elements[4], elements[5], elements[6]),
8 => folder8 !(elements[0], elements[1], elements[2], elements[3], elements[4], elements[5], elements[6], elements[7]),
9 => folder9 !(elements[0], elements[1], elements[2], elements[3], elements[4], elements[5], elements[6], elements[7], elements[8]),
10 => folder10!(elements[0], elements[1], elements[2], elements[3], elements[4], elements[5], elements[6], elements[7], elements[8], elements[9]),
11 => folder11!(elements[0], elements[1], elements[2], elements[3], elements[4], elements[5], elements[6], elements[7], elements[8], elements[9], elements[10]),
12 => folder12!(elements[0], elements[1], elements[2], elements[3], elements[4], elements[5], elements[6], elements[7], elements[8], elements[9], elements[10], elements[11]),
13 => folder13!(elements[0], elements[1], elements[2], elements[3], elements[4], elements[5], elements[6], elements[7], elements[8], elements[9], elements[10], elements[11], elements[12]),
14 => folder14!(elements[0], elements[1], elements[2], elements[3], elements[4], elements[5], elements[6], elements[7], elements[8], elements[9], elements[10], elements[11], elements[12], elements[13]),
15 => folder15!(elements[0], elements[1], elements[2], elements[3], elements[4], elements[5], elements[6], elements[7], elements[8], elements[9], elements[10], elements[11], elements[12], elements[13], elements[14]),
16 => folder16!(elements[0], elements[1], elements[2], elements[3], elements[4], elements[5], elements[6], elements[7], elements[8], elements[9], elements[10], elements[11], elements[12], elements[13], elements[14], elements[15]),
_ => throw new NotSupportedException()
};
case 1:
Debug.Assert(folder1 is not null);
return folder1(elements[0]);
case 2:
Debug.Assert(folder2 is not null);
return folder2(elements[0], elements[1]);
case 3:
Debug.Assert(folder3 is not null);
return folder3(elements[0], elements[1], elements[2]);
case 4:
Debug.Assert(folder4 is not null);
return folder4(elements[0], elements[1], elements[2], elements[3]);
case 5:
Debug.Assert(folder5 is not null);
return folder5(elements[0], elements[1], elements[2], elements[3], elements[4]);
case 6:
Debug.Assert(folder6 is not null);
return folder6(elements[0], elements[1], elements[2], elements[3], elements[4], elements[5]);
case 7:
Debug.Assert(folder7 is not null);
return folder7(elements[0], elements[1], elements[2], elements[3], elements[4], elements[5], elements[6]);
case 8:
Debug.Assert(folder8 is not null);
return folder8(elements[0], elements[1], elements[2], elements[3], elements[4], elements[5], elements[6], elements[7]);
case 9:
Debug.Assert(folder9 is not null);
return folder9(elements[0], elements[1], elements[2], elements[3], elements[4], elements[5], elements[6], elements[7], elements[8]);
case 10:
Debug.Assert(folder10 is not null);
return folder10(elements[0], elements[1], elements[2], elements[3], elements[4], elements[5], elements[6], elements[7], elements[8], elements[9]);
case 11:
Debug.Assert(folder11 is not null);
return folder11(elements[0], elements[1], elements[2], elements[3], elements[4], elements[5], elements[6], elements[7], elements[8], elements[9], elements[10]);
case 12:
Debug.Assert(folder12 is not null);
return folder12(elements[0], elements[1], elements[2], elements[3], elements[4], elements[5], elements[6], elements[7], elements[8], elements[9], elements[10], elements[11]);
case 13:
Debug.Assert(folder13 is not null);
return folder13(elements[0], elements[1], elements[2], elements[3], elements[4], elements[5], elements[6], elements[7], elements[8], elements[9], elements[10], elements[11], elements[12]);
case 14:
Debug.Assert(folder14 is not null);
return folder14(elements[0], elements[1], elements[2], elements[3], elements[4], elements[5], elements[6], elements[7], elements[8], elements[9], elements[10], elements[11], elements[12], elements[13]);
case 15:
Debug.Assert(folder15 is not null);
return folder15(elements[0], elements[1], elements[2], elements[3], elements[4], elements[5], elements[6], elements[7], elements[8], elements[9], elements[10], elements[11], elements[12], elements[13], elements[14]);
case 16:
Debug.Assert(folder16 is not null);
return folder16(elements[0], elements[1], elements[2], elements[3], elements[4], elements[5], elements[6], elements[7], elements[8], elements[9], elements[10], elements[11], elements[12], elements[13], elements[14], elements[15]);
default:
throw new NotSupportedException();
}
}

static readonly Func<int, int, Exception> OnFolderSourceSizeErrorSelector = OnFolderSourceSizeError;
Expand Down
30 changes: 19 additions & 11 deletions MoreLinq/Lookup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,6 @@
// SOFTWARE.
#endregion

#if !NET6_0_OR_GREATER
#nullable enable annotations
#pragma warning disable 8602 // Dereference of a possibly null reference.
#pragma warning disable 8603 // Possible null reference return.
#endif

namespace MoreLinq
{
using System;
Expand Down Expand Up @@ -65,7 +59,11 @@ internal static Lookup<TKey, TElement> Create<TSource>(IEnumerable<TSource> sour
var lookup = new Lookup<TKey, TElement>(comparer);

foreach (var item in source)
lookup.GetGrouping(keySelector(item), create: true)!.Add(elementSelector(item));
{
var grouping = lookup.GetGrouping(keySelector(item), create: true);
Debug.Assert(grouping is not null);
grouping.Add(elementSelector(item));
}

return lookup;
}
Expand All @@ -78,7 +76,11 @@ internal static Lookup<TKey, TElement> Create(IEnumerable<TElement> source, Func
var lookup = new Lookup<TKey, TElement>(comparer);

foreach (var item in source)
lookup.GetGrouping(keySelector(item), create: true)!.Add(item);
{
var grouping = lookup.GetGrouping(keySelector(item), create: true);
Debug.Assert(grouping is not null);
grouping.Add(item);
}

return lookup;
}
Expand All @@ -90,7 +92,11 @@ internal static Lookup<TKey, TElement> CreateForJoin(IEnumerable<TElement> sourc
foreach (var item in source)
{
if (keySelector(item) is { } key)
lookup.GetGrouping(key, create: true)!.Add(item);
{
var grouping = lookup.GetGrouping(key, create: true);
Debug.Assert(grouping is not null);
grouping.Add(item);
}
}

return lookup;
Expand Down Expand Up @@ -179,10 +185,12 @@ void Resize()
{
var newSize = checked((_count * 2) + 1);
var newGroupings = new Grouping<TKey, TElement>[newSize];
var g = _lastGrouping!;
var g = _lastGrouping;
Debug.Assert(g is not null);
do
{
g = g._next!;
g = g._next;
Debug.Assert(g is not null);
var index = g._hashCode % newSize;
g._hashNext = newGroupings[index];
newGroupings[index] = g;
Expand Down
1 change: 0 additions & 1 deletion MoreLinq/Pad.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ namespace MoreLinq
{
using System;
using System.Collections.Generic;
using System.Diagnostics;

static partial class MoreEnumerable
{
Expand Down
3 changes: 2 additions & 1 deletion MoreLinq/PartialSort.cs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,8 @@ static IEnumerable<TSource> PartialSortByImpl<TSource, TKey>(
{
if (keys != null)
{
var key = keySelector!(item);
Debug.Assert(keySelector is not null);
var key = keySelector(item);
if (Insert(keys, key, keyComparer) is {} i)
{
if (top.Count == count)
Expand Down
1 change: 0 additions & 1 deletion MoreLinq/Partition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ namespace MoreLinq
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

static partial class MoreEnumerable
Expand Down
4 changes: 2 additions & 2 deletions MoreLinq/Reactive/Subject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,12 @@ public void OnNext(T value)
}

public void OnError(Exception error) =>
OnFinality(ref _error, error, (observer, err) => observer.OnError(err!));
OnFinality(ref _error, error, (observer, err) => observer.OnError(err));

public void OnCompleted() =>
OnFinality(ref _completed, true, (observer, _) => observer.OnCompleted());

void OnFinality<TState>(ref TState state, TState value, Action<IObserver<T>, TState> action)
void OnFinality<TState>(ref TState? state, TState value, Action<IObserver<T>, TState> action)
{
if (IsMuted)
return;
Expand Down