-
Notifications
You must be signed in to change notification settings - Fork 282
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
Enum class for image types #737
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't get me wrong, I really like this change, but currently this actually modifies how the library behaves (probably only in subtle ways and you are actually improving matters here, so keep reading).
I went spelunking in the code searching for the big switch(ImageType) {}
and wondering how that would work since some image types shared the numeric code. Well, I found it, it's at the top of src/image.cpp
: const Registry registry[]
. Please take a look at the code, but in a nutshell that is an array of structs that contain a "unique ID" (=ImageType
), a function pointer to a constructor and some flags.
The problem is: currently the code chooses for the appropriate constructor by using std::find
on registry
and comparing the image types. That's of completely wrong, since the different image type "codes" that are the same have different flags! For instance a srw
image has currently ImageType = 4
and the flags indicate read-write support. But sr2
images have also id 4 but only supports reading... So one of the two will get the wrong flags.
So: Thank you for switching to enum class, otherwise we would have never found that. Now, what do we do about this? We have two choices:
- Keep the numeric ids the same and retain the same (probably) buggy behavior.
or - Use the PR in it's current form and thereby actually fix
ImageFactory
.
I vote for 2, but that requires at least some additional tests verifying that this works.
And the MinGW build is now broken :(
|
||
TEST(TheImageFactory, createsInstancesForSupportedTypesInMemory) | ||
{ | ||
// Note that the constructor of these Image classes take an 'create' argument |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does this comment mean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand that this comment is quite cryptic ...
I discovered with these characterisation tests that ImageFactory::create
throws for those Image Types which are not using a create
boolean parameter in their constructor ... Compare these two constructors and their related tests:
// Constructors
JpegImage(BasicIo::UniquePtr io, bool create);
explicit BmpImage(BasicIo::UniquePtr io);
// Tests
// Note that the constructor of these Image classes take an 'create' argument
EXPECT_NO_THROW(ImageFactory::create(ImageType::jpeg));
// Note that the constructor of these Image classes does not take an 'create' argument
EXPECT_THROW(ImageFactory::create(ImageType::bmp), Error);
My guess is that some of the authors took care of implementing the functionality for being able to create and save metadata for some Image Types, while others did not do it for some formats (and therefore only the loading functionality is implemented; and writing from existing metadata).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh boy, now I understand.
include/exiv2/image_types.hpp
Outdated
|
||
namespace Exiv2 { | ||
/// Supported Image Formats | ||
enum class ImageType{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EDIT: See the review comment for another view on this.
This is a pretty big API change, as now any client side code that relies on ImageType == 5
being equivalent to ImageType == ImageType::mrw
will stop working.
Don't take me wrong, this is definitely the right way forward! enum class
is for nearly all purposes superior to the classical enum
types. However, I think we should keep the numbers the same.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know this is a big API change but as you already have mentioned the previous behaviour was buggy.
The main problem I see is that it is not possible to keep the same numbers. Take a look here:
https://github.com/Exiv2/exiv2/pull/737/files#diff-5c74f56289aad5a5f43de672abf604a8L40
We had several types sharing the same value ... 🤦♂️
What I could do is to leave the tiff
type with value 4, then continue with the other values that was not define in that file and put at the end of the Enum Type the types:
dng,
nef,
pef,
arw,
sr2,
srw,
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we break the API, break it good so that people who have hardcoded the numbers will find out ASAP.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After continuing working on this, I do not think users will suffer a lot about this change. In case they were using the previous ImageType
namespace, they will need to change it for using the new scoped enum in the form of ImageType::jpeg
. But that's all ... the ImageType type is not used in the API except for the ImageFactory class and not in the most common functions.
I think we can keep that Enum class ordered alphabetically, and the numbers associated to each Image Type will not be very relevant.
I also noticed the Registry stuff and the buggy behaviour, but I forgot to mention it in the PR description. I agree with you in the 2nd choice. I will invest a bit more of time to improve the situation by:
|
I think we should fix the registry/enum. Option 2. Going for |
Sounds great! |
b2388a5
to
9456922
Compare
Codecov Report
@@ Coverage Diff @@
## master #737 +/- ##
=========================================
Coverage ? 70.45%
=========================================
Files ? 144
Lines ? 19193
Branches ? 0
=========================================
Hits ? 13523
Misses ? 5670
Partials ? 0
Continue to review full report at Codecov.
|
I added the tests I promised and I actually did not need to do anything else. Just the single fact of changing to a scoped enum fixed the situation, since it guarantees to have unique integer values associated. All the tests I added worked as I expected. Previously we had some image types sharing the same integer value as @D4N pointed out, and I am sure that this was a buggy behaviour associated. I do not think this bug should worry us in the 0.27 branch. I guess that most of the users are using |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall great work!
Could you just clarify why you started using the EXPECT_*
macros instead of assert? Also, MinGW is still broken :(
@@ -95,6 +95,7 @@ namespace { | |||
AccessMode commentSupport_; | |||
}; | |||
|
|||
/// \todo Use std::unordered_map for implementing the registry. Avoid to use ImageType::none |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
std::array
is imho better here, each element has a unique id and these ids are sequential starting at zero. There's not really a better datastructure for this than an array.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only if you know size at compile time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do, the index is ImageType
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It depends. If we want to conserve a relationship between integer values and ImageTypes, then yes. But is this something we should do? I do not think we need to do it ...
As I commented previously, I do not think this change will have an impact on users since those ImageType values are used mostly internally. I do not see how a user would want to rely in those values in external software. Therefore, I think that std::unordered_map
would be a better option with ImageType
as key, an a Register instance as value. The order of the ImageType
would not matter for the Registry implementation in that way, and we could keep that scope enum sorted alphabetically.
Anyways, I just left the comment there to address this later, and we could discuss about the best way to implement that in other issue/PR 😉
Grrr the situation with the cross-compilation is not fixed. I will need to investigate a bit to be able to compile with mingw locally and document the process. Currently I am having some problems to do it locally. |
If you install the mingw packages (see |
77954a9
to
d74ea12
Compare
- Split test identifying which Images can be created and which not - Add tests for the ImageFactory::create(type, filePath)
d74ea12
to
a3d6fe0
Compare
@D4N Finally the issue with the MinGW compilation is solved. I just needed to cast the enum class type to integer for that output operator. |
@piponazo @D4N You have both shown great determination and tenancy on this. Outstanding. Thank You for making the effort. You'll have seen that @cryptomilk has joined us on Slack. He's going to tutor me on git. I will release v0.27.1 RC1 this week. I'm working with @nehaljwani on the servers which are now on-line. I'm going to ask Andreas Huggel to let me pay to keep exiv2.org alive on AWS. I can use the new servers in in England for Jenkins and release candidates. AWS is stable and reliable, so I'd like to keep that alive. |
After the first positive impressions gathered in #732, I have created this PR in which I just focus in the addition of the enum class
ImageType
to replace the previous namespace in which we were adding global constant values.Note that the characterisation tests have revealed some bugs that I also fixed in this branch.
If you are happy with the changes, and somebody approves the PR, feel free to merge the branch. I will not be available for some days.