Repository navigation
ENH: Select image iterator access by image constness (supersedes #7021) - #7065
Open
hjmjohnson wants to merge 12 commits into
Open
hjmjohnson wants to merge 12 commits into
hjmjohnson wants to merge 12 commits into
Conversation
The original inheritance-based design of the iterator class pairs has several problems, notably the pervasive need to const_cast away the pointer-to-const member whenever an iterator needs write access. This opens up opportunities for accidental or deliberate const-correctness violation. This refactor makes itk::ImageIterator a standalone template class that models both read-only and read/write access semantics based solely on the constness of the template type. ImageConstIterator<T> then functionally acts as an alias template for ImageIterator<const T>. It is implemented as a minimal derived class due to CTAD not being available for alias templates pre-C++20.
ImageIterator<const T> converted only from ImageIterator<T>, so the documented equivalence with ImageConstIterator<T> held one way, and the comparison operators accepted iterators over unrelated images. One trait now states the allowed conversion (same image, never dropping const) for all iterators; comparisons require the same image. C++20 compilers use requires-clauses and operator<=>, and C++26 compilers name the forbidden read-only to writable conversion.
ImageRegionIterator<T> inherited from ImageRegionConstIterator<T> and cast away const to write, so ImageRegionIterator<const T> could write to a const image (InsightSoftwareConsortium#7003). ImageRegionIterator now derives from ImageIterator<T> and writes only when T is not const; ImageRegionConstIterator<T> is ImageRegionIterator<const T>, with deduction guides for smart and raw pointers. Both headers provide both classes.
Apply the ImageRegionIterator design to the scanline pair, so ImageScanlineIterator<const T> cannot write and the const_cast in Set() and Value() goes away.
This was referenced Nov 1, 2026
hjmjohnson
added a commit
to hjmjohnson/ITK
that referenced
this pull request
Nov 1, 2026
# Conflicts: # Modules/Core/Common/include/itkImageRandomConstIteratorWithIndex.h # Modules/Core/Common/include/itkImageRandomConstIteratorWithIndex.hxx
hjmjohnson
marked this pull request as ready for review
November 1, 2026 16:53
This comment was marked as resolved.
This comment was marked as resolved.
This was referenced Nov 1, 2026
hjmjohnson
force-pushed
the
enh-iterator-const-correctness
branch
from
November 1, 2026 19:49
614d0e2 to
6dca3f7
Compare
hjmjohnson
added a commit
to hjmjohnson/ITK
that referenced
this pull request
Nov 1, 2026
# Conflicts: # Modules/Core/Common/include/itkImageRandomConstIteratorWithIndex.h # Modules/Core/Common/include/itkImageRandomConstIteratorWithIndex.hxx
Member
Author
|
@greptileai please review the latest commits (6dca3f7). |
ImageReverseConstIterator offered a public Set() that cast away const, and the writable reverse iterators accepted read-only sources. The four reverse classes now share ImageRegionReverseIterator<T>, writable only when T is not const; the other names derive from it, so every existing method remains except writes through a const image. Conversion from a forward iterator now sets the row span from the current position; before, the span end was computed from a span begin that was not yet set. The GetBufferPointer test now converts from a writable iterator, since conversion from a read-only one is removed.
Apply the ImageIterator design to the root of the WithIndex family: ImageIteratorWithIndex<T> holds the position as a pointer to const pixels only when T is const, so Set() and Value() need no const_cast and are absent for const images. ImageConstIteratorWithIndex<T> is ImageIteratorWithIndex<const T>.
hjmjohnson
force-pushed
the
enh-iterator-const-correctness
branch
from
November 2, 2026 00:09
6dca3f7 to
1e416e2
Compare
hjmjohnson
added a commit
to hjmjohnson/ITK
that referenced
this pull request
Nov 2, 2026
# Conflicts: # Modules/Core/Common/include/itkImageRandomConstIteratorWithIndex.h # Modules/Core/Common/include/itkImageRandomConstIteratorWithIndex.hxx
Member
Author
|
@greptileai please review the latest commits (1e416e2). |
Apply the ImageIteratorWithIndex design to the region, linear, slice, random, random non-repeating, and region exclusion iterators. Each XxxIteratorWithIndex<T> derives from its writable base, inherits the constness-gated Set() and Value(), and XxxConstIteratorWithIndex<T> is XxxIteratorWithIndex<const T>. The random non-repeating conversion deep-copies the permutation it owns.
The frequency-layout iterators and ReflectiveImageRegionIterator inherited from read-only bases and cast away const to write. They now derive from the writable WithIndex iterators, so writes need no cast and are unavailable for const images; each Const name is the iterator over the const image.
LineIterator and PathIterator wrote through a const_cast of the const image held by their read-only bases. Each is now the iterator, writable only when TImage is not const, and the Const name iterates over the const image. PathIterator::Value() read a nonexistent member, so it could not compile; it now returns the current pixel.
The writable flood-filled iterators cast away the const image held by ConditionalConstIterator to write a pixel. They now keep the writable image pointer their constructor receives, offer Set() only for non-const images, and read through the const image without a cast.
Adds compile-time checks that the indexed iterators keep the ITK 5 ImageIteratorDimension constant, that the exclusion iterator can be built from a plain ImageIteratorWithIndex, and that Value() is assignable only for iterators over a non-const image.
hjmjohnson
force-pushed
the
enh-iterator-const-correctness
branch
from
November 2, 2026 04:31
1e416e2 to
3f3d071
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #6141 and fixes #7003: every image iterator now takes its access from the constness of the image type, so
XxxIterator<const ImageType>has noSet()and no writableValue(), and no iterator in the family needsconst_cast. Supersedes #7021, whose commit is the first commit here, authored by @mymonin and kept unchanged.Merge-order note: this conflicts with #7041 in
itkImageRandom*IteratorWithIndex(#7041'sdetail::RandomIndexInRegionmoves with the class intoitkImageRandomIteratorWithIndex.h); whichever lands second needs that one-hunk rebase. Two bugs that this PR exposes but that also exist onmainare fixed separately: #7068 (RandomPermutationassignment loses the shuffled order) and #7069 (reverse region iterator span is one pixel off afterSetIndex()or conversion). This PR takes both fixes on rebase.Design
ImageRegionIterator<TImage>derives fromImageIterator<TImage>, and pixel pointers areconstexactly whenTImageisconst, so writes need no cast.Set()and non-constValue()are removed forconst TImage: SFINAE in C++17, arequiresclause when concepts are available, which gives a "constraints not satisfied" diagnostic.ImageRegionConstIterator<T>is a thin class deriving fromImageRegionIterator<const T>, with deduction guides forSmartPointer,ConstPointer, and raw pointers. Each header provides both names, and theConstheaders and.hxxfiles remain as one-line includes.detail::IsImageIteratorConvertible_vis the single statement of allowed conversions: same image type, never droppingconst.operator==plusoperator<=>instead of six comparison operators; C++26 compilers get= delete("…")naming the forbidden read-only to writable conversion. Both are behind feature-test macros (__cpp_concepts,__cpp_impl_three_way_comparison,__cpp_deleted_function).ConditionalConstIteratorhierarchy.API changes and their measured cost
Removed, each by design:
constimage (const-qualified images can be modified viaitk::ImageRegionIterator<const ImageType>#7003), includingImageReverseConstIterator::Set(), which was public.XxxIterator(const XxxConstIterator &)constructors andoperator=).XxxIterator<T>toXxxConstIterator<T>base-class relation:XxxIterator<T>::Superclassis now the parent iterator, and a function taking a non-constXxxConstIterator<T> &no longer accepts anXxxIterator<T>. Conversion to a read-only iterator is by constructor.Other changes:
ImageReverseIterator,ImageRegionReverseIterator, and theirConstforms now share one class;ImageReverseConstIteratorgainsoperator++.PathIterator::Value()referred to a nonexistent member and could not compile; it now works.ImageIteratorDimensionon the indexed iterators, and construction of the exclusion and frequency iterators from a plainImageIteratorWithIndex.Blast radius, measured in the downstream build forest (ITK with Python wrapping and this branch, merged locally with #7041 and #7056): ANTs builds and passes 179/179, BRAINSTools builds and passes 458/458, and SimpleITK, RTK, Cleaver, Impact, TractographyTRX, and PerformanceBenchmarking build. The failures, in elastix (
vnl_determinant), c3d (removed VNL and orientation APIs), SimpleITKFilters (duplicate target), TubeTK (missing include and members), and several remote modules (deprecatedITK_DISALLOW_COPY_AND_ASSIGN), are identical withmain's headers. No downstream code depended on the removed base-class relation or the writable conversions.Testing
itkImageIteratorsGTest: compile-time checks that every writable iterator hasSet()forImage<int>and not forconst Image<int>, that theConstnames have none, and conversion and comparison rules,Value()assignable only for a non-const image,ImageIteratorDimensionon the indexed iterators, and construction fromImageIteratorWithIndex.itkFrequencyIteratorsGTest: the four frequency iterators accept anyImageIteratorWithIndexover the same image type.-Wall -Wextraunder-std=c++17,c++20,c++23, andc++26with Apple clang 21 and Homebrew clang 23 (exercising both sides of every#if); no GCC was available locally, so GCC's C++20 path is first exercised by CI.ITKCommonandITKImageFrequencysuites pass 738/738pre-commit run --all-filespasses.AI assistance (Claude Code) carried out the conversion with scripts kept for review, ran the probes, and ran the downstream forest; the author reviewed the changes.