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

Fixed Issue#1628 #1629

Merged
merged 23 commits into from
Jun 2, 2021
Merged

Conversation

br3aker
Copy link
Contributor

@br3aker br3aker commented May 14, 2021

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)
  • This PR does not break existing public API in any way

Description

Fixes #1628
Some public properties can't break anything (e.g image size or metadata), they didn't throw before this PR, this behaviour wasn't altered. ToString weren't affected either.

Due to slight internal (within Image class) API change pixel indexer might be a bit more performant: EnsureNotDisposed() call is no longer virtual. Although JIT in some runtimes even could inline such virtual calls in previous versions, it's still a nice change of having one less virtual method I guess.
This change also affects any public method but their calls are too rare to affect performance.

Dmitry Pentin added 15 commits May 13, 2021 22:19
… was disposed, check is delegated to public methods using that property
internal call EnsureNotDisposed is no longer virtual -> micro speedup gain in pixel index accessor Image<TPixel>[x, y].
As Image does not have unmanaged resources and does not implement finalizer method, there's no need for disposable pattern with a pair of Dispose() & Dispose(bool).

Due Dispose(bool) was changed to DisposeManaged().
Subject to discuss.
Image public properties Height, Width, Metadata and PixelType can't corrupt anything if backing image was disposed so I don't see any point altering that behaviour, it wasn't throwing before this branch and shouldn't throw after.
…ensures all operations are called on valid object
@CLAassistant
Copy link

CLAassistant commented May 14, 2021

CLA assistant check
All committers have signed the CLA.

@codecov
Copy link

codecov bot commented May 15, 2021

Codecov Report

Merging #1629 (5d2884e) into master (39697f4) will increase coverage by 0.02%.
The diff coverage is 97.56%.

❗ Current head 5d2884e differs from pull request most recent head afee881. Consider uploading reports for the commit afee881 to get more accurate results
Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1629      +/-   ##
==========================================
+ Coverage   84.12%   84.15%   +0.02%     
==========================================
  Files         812      812              
  Lines       35592    35634      +42     
  Branches     4146     4147       +1     
==========================================
+ Hits        29943    29987      +44     
  Misses       4831     4831              
+ Partials      818      816       -2     
Flag Coverage Δ
unittests 84.15% <97.56%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
src/ImageSharp/ImageFrameCollection{TPixel}.cs 91.40% <92.00%> (+2.12%) ⬆️
src/ImageSharp/Image.cs 95.12% <100.00%> (+1.00%) ⬆️
src/ImageSharp/ImageFrameCollection.cs 96.55% <100.00%> (+6.55%) ⬆️
src/ImageSharp/Image{TPixel}.cs 93.90% <100.00%> (+1.21%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 39697f4...afee881. Read the comment docs.

@JimBobSquarePants
Copy link
Member

I'll get this reviewed ASAP. Thanks for the contribution!

Copy link
Member

@JimBobSquarePants JimBobSquarePants left a comment

Choose a reason for hiding this comment

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

Definitely the right direction but we need to fix up the Disposal pattern changes to match convention and prevent breaking the API.

/// </summary>
/// <param name="disposing">Whether to dispose of managed and unmanaged objects.</param>
protected abstract void Dispose(bool disposing);
protected abstract void DisposeManaged();
Copy link
Member

Choose a reason for hiding this comment

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

This breaks common convention and the API so I can't allow it.

Providing an abstract protected abstract void Dispose(bool disposing) is well documented and should be the pattern we use.

https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#dispose-and-disposebool

src/ImageSharp/Image{TPixel}.cs Outdated Show resolved Hide resolved
public void Save_ObjectDisposedException()
{
var image = new Image<Rgba32>(this.configuration, 10, 10);
var stream = new MemoryStream();
Copy link
Member

Choose a reason for hiding this comment

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

using stream. The fact that the GC cleans up here is an implementation detail.

{
if (this.isDisposed)
{
throw new ObjectDisposedException("Trying to execute an operation on a disposed image.");
Copy link
Member

Choose a reason for hiding this comment

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

We should be using a ThrowHelper here to allow inlining on sealed instances.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You mean ThrowHelper class from ThrowHelper.cs? Should I add ThrowArgumentException method or am I missing something? (there is none as far as I can see :P)

@@ -11,8 +11,10 @@ namespace SixLabors.ImageSharp
/// Encapsulates a pixel-agnostic collection of <see cref="ImageFrame"/> instances
/// that make up an <see cref="Image"/>.
/// </summary>
public abstract class ImageFrameCollection : IEnumerable<ImageFrame>
public abstract class ImageFrameCollection : IDisposable, IEnumerable<ImageFrame>
Copy link
Member

Choose a reason for hiding this comment

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

Wow. I hadn't realized this wasn't already implementing the type. Good catch!

@@ -80,8 +82,14 @@ protected Image(Configuration configuration, PixelTypeInfo pixelType, ImageMetad
/// <inheritdoc />
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
Copy link
Member

Choose a reason for hiding this comment

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

We shouldn't be removing the finalizer suppression in the base class.

https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#the-dispose-method

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Didn't know SuppressFinalize do nothing if type has no finalizer, thanks!

throw new ObjectDisposedException("Trying to execute an operation on a disposed image.");
}
}
protected override void DisposeManaged() => this.frames.Dispose();
Copy link
Member

Choose a reason for hiding this comment

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

The original pattern was correct here.

@br3aker
Copy link
Contributor Author

br3aker commented May 21, 2021

@JimBobSquarePants seems like I've messed up with ThrowHelper from shared infrastructure. Although I'd added it locally, I've totally missed that it wasn't in the commit and it isn't tracked by git now. How to fix it?
First time working with such a huge project, sorry for being such a burden.

@JimBobSquarePants
Copy link
Member

First time working with such a huge project, sorry for being such a burden.

Not at all!! You're contributions are most welcome!

That's my mistake for not being clear. ThrowHelper in the ShareInfrastructure project cannot be edited (As it's included via a submodule) but it is a partial so I would make another part for that class in the ImageSharp project and add your method there.

@br3aker
Copy link
Contributor Author

br3aker commented May 22, 2021

Got it, thanks for answering yet another question!

@JimBobSquarePants
Copy link
Member

JimBobSquarePants commented Jun 2, 2021

@br3aker Can you please give me write access to your fork. For some reason I'm unable to push directly to your PR so we can complete this.

https://docs.github.com/en/github/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork

@br3aker
Copy link
Contributor Author

br3aker commented Jun 2, 2021

@JimBobSquarePants that's strange. Edit was enabled from the start, I re-checked it now, can you try it again please?

@JimBobSquarePants
Copy link
Member

@br3aker This isn't the first PR I've had issues with and I'm not sure why it happens. I tried again and it didn't work. The last time the contributor had to explicitly invite me as a contributor to the repo as a workaround.

@br3aker
Copy link
Contributor Author

br3aker commented Jun 2, 2021

@JimBobSquarePants invite sent, thanks for fixing this!

Copy link
Member

@JimBobSquarePants JimBobSquarePants left a comment

Choose a reason for hiding this comment

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

LGTM 👍 Thanks!

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.

Image & underlying ImageFrameCollection aren't behaving like they were disposed after calling Dispose()
3 participants