-
Notifications
You must be signed in to change notification settings - Fork 5
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
Evaluate tensorstoreToITKComponentType
at compile-time, using constexpr
#68
base: main
Are you sure you want to change the base?
Evaluate tensorstoreToITKComponentType
at compile-time, using constexpr
#68
Conversation
Following Scott Meyers, Effective Modern C++, 2014, "Use `constexpr` whenever possible".
Ensures that `tensorstoreToITKComponentType` is evaluated at compile-time, by introducing a constexpr variable template, `toITKComponentType<T>`.
5e723a5
to
6678cc4
Compare
@@ -602,11 +606,10 @@ OMEZarrNGFFImageIO::ReadImageInformation() | |||
} | |||
|
|||
// We call tensorstoreToITKComponentType for each type. | |||
// Hopefully compiler will optimize it away via constant propagation and inlining. |
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.
This PR proposes to remove the comment saying that "hopefully compiler will optimize it away", as the compiler will optimize it away now, with this commit! If I understand correctly!
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.
Perhaps leave the comment, just change it? "Compiler should optimize away all unused branches"?
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.
Thanks for the suggestion, @dzenanz but I'm not entirely sure. It now (originally) says:
We call tensorstoreToITKComponentType for each type. Hopefully compiler will optimize it away [...]
In this case, "it" refers to the tensorstoreToITKComponentType calls, right? Those are certainly optimized away, with this PR.
Which unused branches do you refer to?
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.
tensorstoreToITKComponentType
calls have many if-else branches.
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.
Do you mean that tensorstoreToITKComponentType
has many case
's? As in:
ITKIOOMEZarrNGFF/src/itkOMEZarrNGFFImageIO.cxx
Lines 139 to 178 in 98a43d0
tensorstoreToITKComponentType(const tensorstore::DataType dtype) | |
{ | |
switch (dtype.id()) | |
{ | |
case tensorstore::DataTypeId::char_t: | |
case tensorstore::DataTypeId::int8_t: | |
return IOComponentEnum::CHAR; | |
case tensorstore::DataTypeId::byte_t: | |
case tensorstore::DataTypeId::uint8_t: | |
return IOComponentEnum::UCHAR; | |
case tensorstore::DataTypeId::int16_t: | |
return IOComponentEnum::SHORT; | |
case tensorstore::DataTypeId::uint16_t: | |
return IOComponentEnum::USHORT; | |
case tensorstore::DataTypeId::int32_t: | |
return IOComponentEnum::INT; | |
case tensorstore::DataTypeId::uint32_t: | |
return IOComponentEnum::UINT; | |
case tensorstore::DataTypeId::int64_t: | |
return IOComponentEnum::LONGLONG; | |
case tensorstore::DataTypeId::uint64_t: | |
return IOComponentEnum::ULONGLONG; | |
case tensorstore::DataTypeId::float32_t: | |
return IOComponentEnum::FLOAT; | |
case tensorstore::DataTypeId::float64_t: | |
return IOComponentEnum::DOUBLE; | |
default: | |
return IOComponentEnum::UNKNOWNCOMPONENTTYPE; | |
} | |
} |
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.
Both that and
ITKIOOMEZarrNGFF/src/itkOMEZarrNGFFImageIO.cxx
Lines 641 to 650 in 98a43d0
READ_ELEMENT_IF(int8_t) | |
READ_ELEMENT_IF(uint8_t) | |
READ_ELEMENT_IF(int16_t) | |
READ_ELEMENT_IF(uint16_t) | |
READ_ELEMENT_IF(int32_t) | |
READ_ELEMENT_IF(uint32_t) | |
READ_ELEMENT_IF(int64_t) | |
READ_ELEMENT_IF(uint64_t) | |
READ_ELEMENT_IF(float) | |
READ_ELEMENT_IF(double) |
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.
- The other PR that I submitted (Replace READ_ELEMENT_IF with variadic template, move functions into unnamed namespace #67) proposes to the sequence of
READ_ELEMENT_IF
calls. So then those if-else branches are also addressed 😃
@@ -602,11 +606,10 @@ OMEZarrNGFFImageIO::ReadImageInformation() | |||
} | |||
|
|||
// We call tensorstoreToITKComponentType for each type. | |||
// Hopefully compiler will optimize it away via constant propagation and inlining. |
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.
Perhaps leave the comment, just change it? "Compiler should optimize away all unused branches"?
@@ -135,7 +135,7 @@ OMEZarrNGFFImageIO::PrintSelf(std::ostream & os, Indent indent) const | |||
os << indent << "ChannelIndex: " << m_ChannelIndex << std::endl; | |||
} | |||
|
|||
IOComponentEnum | |||
constexpr IOComponentEnum | |||
tensorstoreToITKComponentType(const tensorstore::DataType dtype) | |||
{ | |||
switch (dtype.id()) |
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.
Interesting compile errors from Ubuntu/GCC, https://open.cdash.org/viewBuildError.php?buildid=9845800 at this particular dtype.id()
call:
itkOMEZarrNGFFImageIO.cxx: In instantiation of 'constexpr const IOComponentEnum itk::toITKComponentType<float>':
itkOMEZarrNGFFImageIO.cxx:643:3: required from here
itkOMEZarrNGFFImageIO.cxx:251:84: in 'constexpr' expansion of 'itk::tensorstoreToITKComponentType(tensorstore::dtype_v<float>.tensorstore::StaticDataType<float>::operator tensorstore::DataType())'
itkOMEZarrNGFFImageIO.cxx:141:19: in 'constexpr' expansion of 'dtype.tensorstore::DataType::id()'
itkOMEZarrNGFFImageIO.cxx:251:34: error: the value of 'tensorstore::internal_data_type::MakeDataTypeOperations<float>::operations' is not usable in a constant expression
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.
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.
Just fixed, by google/tensorstore@91ea2a2 😃
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.
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.
template <typename T> | ||
static constexpr IOComponentEnum toITKComponentType = tensorstoreToITKComponentType(tensorstore::dtype_v<T>); |
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 could bypass the troublesome compile-time evaluation of tensorstoreToITKComponentType/tensorstore::DataType::id() by defining the variable template as follows:
template <typename T>
static constexpr IOComponentEnum toITKComponentType =
std::is_same_v<T, int8_t> ? IOComponentEnum::CHAR :
std::is_same_v<T, uint8_t> ? IOComponentEnum::UCHAR :
std::is_same_v<T, int16_t> ? IOComponentEnum::SHORT :
std::is_same_v<T, uint16_t> ? IOComponentEnum::USHORT :
std::is_same_v<T, int32_t> ? IOComponentEnum::INT :
std::is_same_v<T, uint32_t> ? IOComponentEnum::UINT :
std::is_same_v<T, int64_t> ? IOComponentEnum::LONGLONG :
std::is_same_v<T, uint64_t> ? IOComponentEnum::ULONGLONG :
std::is_same_v<T, float> ? IOComponentEnum::FLOAT :
std::is_same_v<T, double> ? IOComponentEnum::DOUBLE :
IOComponentEnum::UNKNOWNCOMPONENTTYPE;
Do we like that? 🤔
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 is probably better if they fix it. Let's wait a few days?
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.
OK, let's wait a few days 👍 By the way, clang-format would make the "is_same_v based" definition from #68 (comment) look like this:
template <typename T>
static constexpr IOComponentEnum toITKComponentType =
std::is_same_v<T, int8_t>
? IOComponentEnum::CHAR
: std::is_same_v<T, uint8_t>
? IOComponentEnum::UCHAR
: std::is_same_v<T, int16_t>
? IOComponentEnum::SHORT
: std::is_same_v<T, uint16_t>
? IOComponentEnum::USHORT
: std::is_same_v<T, int32_t>
? IOComponentEnum::INT
: std::is_same_v<T, uint32_t>
? IOComponentEnum::UINT
: std::is_same_v<T, int64_t>
? IOComponentEnum::LONGLONG
: std::is_same_v<T, uint64_t>
? IOComponentEnum::ULONGLONG
: std::is_same_v<T, float>
? IOComponentEnum::FLOAT
: std::is_same_v<T, double> ? IOComponentEnum::DOUBLE
: IOComponentEnum::UNKNOWNCOMPONENTTYPE;
Wonderful, isn't is? 😸
This pull request forces the compiler to evaluate the
tensorstoreToITKComponentType
calls at compile-time, both inOMEZarrNGFFImageIO::Read
andOMEZarrNGFFImageIO::Write
. It might yield a small performance improvement. Otherwise, it's at least a nice-to-have 😃Might prevent compiler/code analysis warnings like "This function function-name could be marked
constexpr
if compile-time evaluation is desired (f.4)", https://learn.microsoft.com/en-us/cpp/code-quality/c26497?view=msvc-170When reviewing the code changes, it may be helpful to skip whitespace changes: https://github.com/InsightSoftwareConsortium/ITKIOOMEZarrNGFF/pull/68/files?w=1