perf: replace vector-returning iteration methods with lazy ranges (P1 + A2)#36
Merged
csparker247 merged 3 commits intodevelopfrom Mar 16, 2026
Merged
perf: replace vector-returning iteration methods with lazy ranges (P1 + A2)#36csparker247 merged 3 commits intodevelopfrom
csparker247 merged 3 commits intodevelopfrom
Conversation
…, A2) Eliminates hot-path heap allocations in the ABF/ABFPlusPlus solver loops by replacing all vector-copying mesh iteration methods with zero-allocation alternatives: - vertices()/faces() now return const vector references (zero copy) - edges() returns a lazy Range<EdgesIterator> flattening face→edge traversal - vertices_interior()/vertices_boundary() return Range<FilteringIterator> - Vertex::wheel() returns Range<WheelIterator> (linked-list iterator) - Face::edges() added as a named iterable accessor, resolving A2 New iterator types (WheelIterator, EdgesIterator) are private nested classes in HalfEdgeMesh modeled on the existing FaceIterator. detail::Range<Iter> and detail::FilteringIterator<Iter,Pred> are added to the detail namespace. Callers are syntactically unchanged except AngleBasedLSCM which changes vertices_boundary()[0] to vertices_boundary().front(). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- IterateEdgesCount: verify edges() yields exactly 3*num_faces() half-edges - IterateWheelBoundaryVertex: wheel() on a boundary vertex terminates correctly - IterateWheelReIterable: Range is re-iterable (two passes yield same results) - IterateNoInteriorVertices: vertices_interior().empty() on a triangle mesh - RangeFrontEmpty: Range::front() and Range::empty() correctness Also removes (resolves A2) track reference from Face::edges() docstring. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All three resolved by PR #36 (perf/p1-lazy-iteration). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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.
Summary
face->edges()named iterable accessor, resolving the awkward*facedereference patternInitializeAnglesAndWeightsalready callsv->wheel()exactly once and stores the result; with P1's re-iterableRange<WheelIterator>, no allocation or redundancy remainsChanges
vertices()std::vector<VertPtr>(copy)const std::vector<VertPtr>&faces()std::vector<FacePtr>(copy)const std::vector<FacePtr>&edges()std::vector<EdgePtr>(built per call)Range<EdgesIterator>(lazy)vertices_interior()std::vector<VertPtr>(filtered copy)Range<FilteringIterator<...>>vertices_boundary()std::vector<VertPtr>(filtered copy)Range<FilteringIterator<...>>Vertex::wheel()std::vector<EdgePtr>(built per call)Range<WheelIterator>(lazy)Face::edges()Range<FaceIterator>New types (all in
HalfEdgeMesh.hpp)detail::Range<Iter>— lightweight begin/end wrapper supporting range-for,.empty(),.front()detail::FilteringIterator<Iter, Pred>— input iterator skipping non-matching elementsWheelIterator<Const>— linked-list walk around a vertex (edge->pair->nextchain), skipping boundary edgesEdgesIterator<Const>— lazily flattens all face edges across all facesAll existing call sites are syntactically unchanged (range-for,
.size(),.num_*()) exceptAngleBasedLSCM::Computewhich changesvertices_boundary()[0]→vertices_boundary().front().Kept as vector-returning (not hot path):
outgoing_edges(),incoming_edges(),boundaries(),connected_components().Test plan
TestHalfEdgeMesh.cpp:IterateVertices,IterateFaces,IterateEdges,IterateEdgesCount,IterateInteriorBoundaryPartition,IterateWheel,IterateWheelBoundaryVertex,IterateWheelReIterable,IterateNoInteriorVertices,RangeFrontEmpty,FaceEdgesgit clang-formatappliedCloses #4, Closes #14
🤖 Generated with Claude Code