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

ENH: ImageRegion support C++17 structured binding #4367

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/itk_dict.txt
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ Minc
MincTransformIO
Minkowski
Musser
NOLINTBEGIN
NOLINTEND
NVidia
Negahdaripour
Newmark
Expand Down Expand Up @@ -279,6 +281,7 @@ callosum
centerline
cdf
cdfs
cert
cfl
cgi
cha
Expand All @@ -303,6 +306,7 @@ confocal
cooccurrence
costless
cp
cpp
cr
cranio
creativecommons
Expand All @@ -322,6 +326,7 @@ d'Attente
dDwWmMyY
da
dat
dcl
dcmimage
dcmtk
datablock
Expand Down
64 changes: 64 additions & 0 deletions Modules/Core/Common/include/itkImageRegion.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
#include "itkSize.h"
#include "itkContinuousIndex.h"
#include "itkMath.h"
#include <type_traits> // For conditional and integral_constant.
#include <utility> // For tuple_element and tuple_size.

// Macro added to each `ImageRegion` member function that overrides a virtual member function of `Region`. In the
// future, `ImageRegion` will no longer inherit from `Region`, so then those `ImageRegion` member functions will no
Expand Down Expand Up @@ -357,6 +359,39 @@ class ITK_TEMPLATE_EXPORT ImageRegion final
SliceRegion
Slice(const unsigned int dim) const;

/** Supports tuple-like access: `get<0>()` returns a reference to the index and `get<1>()` returns a reference to the
* size of the region. */
template <size_t VTupleIndex>
[[nodiscard]] auto &
get()
{
if constexpr (VTupleIndex == 0)
{
return m_Index;
}
else
{
static_assert(VTupleIndex == 1);
return m_Size;
}
}

/** Supports tuple-like access. Const overload. */
template <size_t VTupleIndex>
[[nodiscard]] const auto &
get() const
{
if constexpr (VTupleIndex == 0)
{
return m_Index;
}
else
{
static_assert(VTupleIndex == 1);
return m_Size;
}
}

protected:
/** Methods invoked by Print() to print information about the object
* including superclasses. Typically not called by the user (use Print()
Expand All @@ -378,6 +413,35 @@ std::ostream &
operator<<(std::ostream & os, const ImageRegion<VImageDimension> & region);
} // end namespace itk


namespace std
{
// NOLINTBEGIN(cert-dcl58-cpp)
// Locally suppressed the following warning from Clang-Tidy (LLVM 17.0.1), as it appears undeserved.
// > warning: modification of 'std' namespace can result in undefined behavior [cert-dcl58-cpp]
N-Dekker marked this conversation as resolved.
Show resolved Hide resolved

/** `std::tuple_size` specialization, needed for ImageRegion to support C++ structured binding.
*
* Example, using structured binding to retrieve the index and size of a region:
\code
auto [index, size] = image.GetRequestedRegion();
\endcode
*/
template <unsigned int VImageDimension>
struct tuple_size<itk::ImageRegion<VImageDimension>> : integral_constant<size_t, 2>
{};

/** `std::tuple_element` specialization, needed for ImageRegion to support C++ structured binding. */
template <size_t VTupleIndex, unsigned int VImageDimension>
struct tuple_element<VTupleIndex, itk::ImageRegion<VImageDimension>>
: conditional<VTupleIndex == 0, itk::Index<VImageDimension>, itk::Size<VImageDimension>>
{
static_assert(VTupleIndex < tuple_size_v<itk::ImageRegion<VImageDimension>>);
};

// NOLINTEND(cert-dcl58-cpp)
} // namespace std

#undef itkRegionOverrideMacro

#ifndef ITK_MANUAL_INSTANTIATION
Expand Down
25 changes: 25 additions & 0 deletions Modules/Core/Common/test/itkImageRegionGTest.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,28 @@ TEST(ImageRegion, CropLargerToSmallerRegionAndViceVersa)
}
}
}


// Tests C++ structured binding of an ImageRegion.
TEST(ImageRegion, SupportsStructuredBinding)
{
using RegionType = itk::ImageRegion<2>;
using IndexType = RegionType::IndexType;
using SizeType = RegionType::SizeType;

RegionType region{};
auto && [index, size] = region;

static_assert(std::is_same_v<decltype(index), IndexType>);
static_assert(std::is_same_v<decltype(size), SizeType>);
EXPECT_EQ(&index, &(region.GetIndex()));
EXPECT_EQ(&size, &(region.GetSize()));

const RegionType constRegion{};
auto && [constIndex, constSize] = constRegion;

static_assert(std::is_same_v<decltype(constIndex), const IndexType>);
static_assert(std::is_same_v<decltype(constSize), const SizeType>);
EXPECT_EQ(&constIndex, &(constRegion.GetIndex()));
EXPECT_EQ(&constSize, &(constRegion.GetSize()));
}