Skip to content

Conversation

@JimBobSquarePants
Copy link
Member

Prerequisites

  • I have written a descriptive pull-request title
  • I have verified that there are no overlapping pull-requests open
  • I have verified that I am following the existing coding patterns and practice as demonstrated in the repository. These follow strict Stylecop rules 👮.
  • I have provided test coverage for my change (where applicable)

Description

Removes all obsolete conditions, obsolete methods, and fixes all compiler warnings.

@JimBobSquarePants JimBobSquarePants requested a review from a team July 25, 2022 07:36
@JimBobSquarePants JimBobSquarePants changed the title Js/remove obsolete code Remove obsolete code Jul 25, 2022
@JimBobSquarePants JimBobSquarePants added this to the 3.0.0 milestone Jul 25, 2022
Copy link
Contributor

@gfoidl gfoidl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes per-se LGTM, but I expect there will be some perf-regression. See comment about Span.Slice vs Range operator.
Maybe you can write a comment on the Roslyn-issue to help them prioritize that one 😉

{
// Vector4 fits neatly in pairs. Any overlap has to be equal to 1.
Expand(ref MemoryMarshal.GetReference(vectors.Slice(vectors.Length - 1)));
Expand(ref MemoryMarshal.GetReference(vectors[^1..]));
Copy link
Contributor

@gfoidl gfoidl Jul 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old version may be more performant, unfortunately. This is tracked in dotnet/roslyn#43598, and you can see the difference in this sharplab.

If it's not perf-sensitive, then got with the new code, as it's cleaner to read.
Edit: this goes through that whole PR, there are definitely some hot places where this will have negative impact.
If Roslyn tackles that issue, perf will increase "for free".

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤦‍♂️ This is so frustrating. Why introduce an analyser that promotes worse behaviour?

a = b;
b = tmp;
}
static void Swap(ref short a, ref short b) => (b, a) = (a, b);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just as info:
Resulting machine code will be the same, but the IL-size is with the tuple-based approach a bit larger than with the local (old version).

I don't think it matters here, but potential drawbacks

  • JIT may give up inlining if any budget may exceed earlier --> add MethodImpl.AggressiveInlining (or the ImageSharp-equivalent) to be on the safe side?
  • on products where IL size matters this could have a negative effect (TBH I don't know if two bytes more or less count here, as the reduction overall is much bigger that this PR does, but just to point it out)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another poor analyser suggestion 😔

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm no compiler engineer*, but for me this pattern is easy to recognize, so "optimal" code should be emitted, even if Roslyn isn't a optimizing compiler (that's the role of the JIT), but regarding IL-size optimizations count towards Roslyn.

* so I have somewhat limited understanding on how things work there


int zeroIndex = data.IndexOf((byte)0);
if (zeroIndex < PngConstants.MinTextKeywordLength || zeroIndex > PngConstants.MaxTextKeywordLength)
if (zeroIndex is < PngConstants.MinTextKeywordLength or > PngConstants.MaxTextKeywordLength)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just FYI: dotnet/roslyn#60534

I'd leave the code as is, as it's basically the same as now just nicer to read. When Roslyn got that addressed the perf-goodness comes "for free".

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MO ANALYZERS MO PROBLEMS

Vp8ModeScore tmp = rdCur;
rdCur = rdBest;
rdBest = tmp;
(rdBest, rdCur) = (rdCur, rdBest);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the swap-method from above (where I commented) instead (needs to be made generic then)?
Or drop the swap-method and write the one-line directly?

I don't have a strong opinion what's better here, but it should be consistent.
Leaning towards swap-method, as if there's a super nice trick once on how to swap more efficiently only one place needs to be updated.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 good idea

Copy link
Member

@antonfirsov antonfirsov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, but somewhat concerned about var rules.


Vector<ushort> u0 = Vector.Narrow(w0, w1);
Vector<ushort> u1 = Vector.Narrow(w2, w3);
var u0 = Vector.Narrow(w0, w1);
Copy link
Member

@antonfirsov antonfirsov Sep 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case of arrays the PR replaces var with the more specific T[] on the left side, which feels like an inconsistent configuration of rules, and personally I always prefer to have the type information around in case of primitive types. It's not immediately obvious what does Narrow return here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ve really struggled to get editorconfig to do what I want here (var rules are actually unchanged). This seems to fall under the “type is apparent” rule. There’s actually been a warning sitting in the code there for years, it just was ignored.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why arrays aren’t considered apparent I simply do not know.

Copy link
Member

@antonfirsov antonfirsov Sep 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's "apparent" when a non-generic method on a non-generic type returns a variable with a generic type of the same name. The lack of the type argument hurts readability, especially with API-s like Vector.Narrow. Is there a way to fine-tune this rule so it doesn't kick in for these cases? What if we disable it entirely?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm gonna create an empty project and see if I can get the rules working using the VS editorconfig editor and a fresh file.

Copy link
Member Author

@JimBobSquarePants JimBobSquarePants Sep 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's var turned off everywhere. It's verbose as hell but at least it's consistent.

image

Here's with "when type is apparent"

This one is annoying because the byte[] declaration should be apparent and the Vector.Narrow(...) return value isn't
image

Here's "when type is apparent" and "built in types"

This one is annoying because the double and int primitives are not apparent in my opinion since they require the reader to know the syntax declaration rules on the right hand side.

image

Which do you prefer?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I may be very oldscool, but for me the first one is the lesser evil. I wonder what do others think @SixLabors/core?

This rule/analyzer (IDE0007?) really sucks. I wonder if there is a better way to raise awareness about it than posting on https://developercommunity.visualstudio.com/ which is a straight way to oblivion.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree and with the forcing of target type new we handle known types. I'll implement that.

There's actually 2 issues in Roslyn around this. (One closed as a duplicate)

dotnet/roslyn#23714
dotnet/roslyn#55722

I wish I could do this though. It's really annoying that I can't seem to find a way.

byte[] b = [10];

// <auto-generated />

<#
// Note use of MethodImplOptions.NoInlining. We have tests that are failing on certain architectures when
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this was specific to old runtimes?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep. All fixed now 😀

</PropertyGroup>

<PropertyGroup>
<CodeAnalysisRuleSet>..\ImageSharp.ruleset</CodeAnalysisRuleSet>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tend to only use forward slashes now because Windows now also supports that.

VerticalPred(dst.Slice(I16VE16), top, 16);
HorizontalPred(dst.Slice(I16HE16), left, 16);
TrueMotion(dst.Slice(I16TM16), left, top, 16);
DcMode(dst[..], left, top, 16, 16, 5);
Copy link
Member

@dlemstra dlemstra Sep 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I16DC16 seems to be missing here?

Turns out that I16DC16 is always zero. And that is probably why it was removed?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll re read the change.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for a slice at all so just pass dst

Copy link
Member

@dlemstra dlemstra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made a couple extra commits and I think we are good to go now for a merge.

Configuration configuration,
ReadOnlySpan<Color> source,
Span<TPixel> destination)
public static void ToPixel<TPixel>(ReadOnlySpan<Color> source, Span<TPixel> destination)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a breaking change in the Api? Should we not limit this PR to only remove non breaking changes?

Copy link
Member

@antonfirsov antonfirsov Sep 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added Configuration to the parameter list to enable the optimization of this method by utilizing the PixelOperations<TPixel>.FromRgba64() batch conversion method. The abstract PixelOperations<TPixel> methods take Configuration for the case the implementation decides to refer to Configuration.MemoryAllocator to allocate temporary buffers.

If we don't like / don't need this pattern, we can open an issue to re-evaluate the design, after carefully analyzing our current conversion methods, which no longer need special logic for .NET Framework, though we may need to account for non-Intel, non-coreclr targets.

But I would avoid making sneaky public API changes in a big refactor PR. Is this the only one ore is there more?

Copy link
Member Author

@JimBobSquarePants JimBobSquarePants Sep 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's re-add it for now then and add a TODO in the code so intent is known.

Is this the only one ore is there more?

Some of the methods on ColorSpaceConverter are now static. I want to keep them like that though.

remaining -= JFifMarker.Length;

JFifMarker.TryParse(this.temp, out this.jFif);
_ = JFifMarker.TryParse(this.temp, out this.jFif);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we not handle this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, you're right. Now explicitly throwing NotSupportedException since we only support JFIF App0 markers.

@JimBobSquarePants
Copy link
Member Author

I'm gonna merge this now. All tests are passing, and I've covered any raised issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants