ENH: Let MetaDataDictionary support non-equality-comparable data#3307
ENH: Let MetaDataDictionary support non-equality-comparable data#3307N-Dekker wants to merge 1 commit intoInsightSoftwareConsortium:masterfrom
MetaDataDictionary support non-equality-comparable data#3307Conversation
Follow-up to: pull request InsightSoftwareConsortium#2246 commit 694bbc0 "ENH: Add operator==, operator!= to MetaDataObject and MetaDataDictionary"
|
@Leengit Please have a look at my SFINAE 😸 You know, I always try to avoid it, but this time I just could not resist the magic of Substitution Failure Is Not An Error 😄 What do you think? |
|
Hmmm... 🤔 this pull request may not add much if we only want to support the MetaDataObject template instantiations declared at ITK/Modules/Core/Common/include/itkMetaDataObject.h Lines 298 to 321 in 24e7b45 |
| operator==(const Self & lhs, const Self & rhs) | ||
| { | ||
| return lhs.m_MetaDataObjectValue == rhs.m_MetaDataObjectValue; | ||
| return EqualMetaDataObjects(&lhs.m_MetaDataObjectValue, &rhs.m_MetaDataObjectValue); |
There was a problem hiding this comment.
I would consider passing these in by reference rather than as const pointers. That mimics typical operator== convention. Also, it discourages nullptr as an argument to EqualMetaDataObjects.
There was a problem hiding this comment.
@Leengit In general, I also prefer pass by reference rather than by pointer. But EqualMetaDataObjects is just an internal private helper function overload set, so it does not matter so much. And in this case it is actually essential that the parameters are pointer! The idea is that by providing an overload for void pointers, the compiler must do overload resolution. The overload for void pointers is less specific than the one for const TMetaDataObject *, so the compiler will always select the one for const TMetaDataObject *... except when the one for const TMetaDataObject * is SFINAE-ed away!
So only when SFINAE has removed the const TMetaDataObject * specific overload, the compiler will select the void pointer overload to be called. OK?
SFINAE removes the const TMetaDataObject * specific overload when the expression decltype(*lhs == *rh) is invalid ("substitution failure") for that specific TMetaDataObject type.
| return *lhs == *rhs; | ||
| } | ||
|
|
||
| /** Overload for MetaDataObject types that do not have an `operator==`.*/ |
There was a problem hiding this comment.
I fear that in the case that operator== does exist, this code will produce two versions of EqualMetaDataObjects. If the testing code works on all platforms then those two versions are not considered redefinitions of each other, but it may be difficult to know which of the two the compiler is choosing. If the testing is working then maybe my fears are unfounded.
If EqualMetaDataObjects were a class instead of a function then we could put the second version here as the default implementation and the first version here as a template specialization.
There was a problem hiding this comment.
If the testing code works on all platforms then those two versions are not considered redefinitions of each other, but it may be difficult to know which of the two the compiler is choosing. If the testing is working then maybe my fears are unfounded.
Just to be 100% sure, I did specifically extend the existing MetaDataDictionary.Equal unit tests to check comparing dictionaries after storing an std::string. Because std::string is an obvious example for which operator== is very different from a bitwise comparison (memcmp). Luckily, the tests are passing successfully 😃
| static bool | ||
| EqualMetaDataObjects(const void * const lhs, const void * const rhs) | ||
| { | ||
| return std::memcmp(lhs, rhs, sizeof(MetaDataObjectType)) == 0; |
There was a problem hiding this comment.
Apologies for my ignorance, but I see a hard-coded MetaDataObjectType here but a seemingly more flexible TMetaDataObject in the first implementation of EqualMetaDataObjects. I mention that just in case that is not what is intended.
There was a problem hiding this comment.
Never mind. I see that MetaDataObjectType is the template parameter of the class. (Even though it does not start with T.)
|
This PR was intended to more easily allow storing simple data structs into the ITK/Modules/ThirdParty/NIFTI/src/nifti/niftilib/nifti1_io.h Lines 58 to 60 in f372040 The idea was that it would allow passing such a data struct directly to ITK/Modules/IO/NIFTI/src/itkNiftiImageIO.cxx Lines 1002 to 1010 in 9eb4c12 Those nine lines of code could then be replaced by one line, as follows: Of course, if such simple data structs are not meant to be supported by |
|
This PR is probably useful, even if its immediate use no longer exists. |
It would actually useful if we would add an instantiation of ITK/Modules/Core/Common/include/itkMetaDataObject.h Lines 298 to 321 in 24e7b45 Is |
Again, I think that's a bad idea. It would be exporting a private niftilib struct as public ITK API. Sure, it'd be nice if |
I think it would be feasible to add support for N-dimensional C-style arrays to ITK/Modules/Core/Common/include/itkMetaDataObject.hxx Lines 55 to 60 in f84720e In pseudo code, it might be: This would allow encapsulating "qto_xyz" as a 2-D C-style array, as follows (mind the |
Right; storing |
|
Related PR: #3320 "ENH: Support C-style arrays as MetaDataObjectType for MetaDataDictionary" |
|
Honestly I feel that it's a bit of a hack, to use bitwise comparison (memcmp) whenever the type of the stored objects does not support So I would prefer to only move this PR forward if or when we really have an actual use case. Especially now that we already have added C-array support, with 7299e5c |
|
Should we close it, or keep at as draft indefinitely? |
Close-without-merge would be OK to me now. Note that the current implementation conflicts with 7299e5c (Support C-style arrays as MetaDataObjectType for MetaDataDictionary), but of course, this conflict could be resolved whenever necessary. |
|
I am facing an issue related to this in Python wrappings. But for "qto_xyz" key the dict method fails for the Python object. I wanted to know what would be the best way to handle this in ITK Python. |
No longer require
operator==for the types of values stored initk::MetaDataDictionary.Follow-up to:
pull request #2246
commit 694bbc0
"ENH: Add operator==, operator!= to MetaDataObject and MetaDataDictionary"