83
83
. count ( )
84
84
} ;
85
85
86
+ // Binary or otherwise empty?
87
+ if num_lines_in_blamed == 0 {
88
+ return Ok ( Outcome :: default ( ) ) ;
89
+ }
90
+
86
91
let mut hunks_to_blame = vec ! [ {
87
92
let range_in_blamed_file = 0 ..num_lines_in_blamed as u32 ;
88
93
UnblamedHunk {
94
99
let mut out = Vec :: new ( ) ;
95
100
let mut diff_state = gix_diff:: tree:: State :: default ( ) ;
96
101
' outer: while let Some ( item) = traverse. next ( ) {
102
+ if hunks_to_blame. is_empty ( ) {
103
+ break ;
104
+ }
97
105
let commit = item. map_err ( |err| Error :: Traverse ( err. into ( ) ) ) ?;
98
106
let suspect = commit. id ;
99
107
stats. commits_traversed += 1 ;
@@ -106,12 +114,13 @@ where
106
114
// remaining lines to it, even though we don’t explicitly check whether that is true
107
115
// here. We could perhaps use diff-tree-to-tree to compare `suspect`
108
116
// against an empty tree to validate this assumption.
109
- unblamed_to_out ( & mut hunks_to_blame, & mut out, suspect) ;
110
- break ;
111
- } else {
112
- // There is more, keep looking.
113
- continue ;
117
+ if unblamed_to_out_is_done ( & mut hunks_to_blame, & mut out, suspect) {
118
+ break ' outer;
119
+ }
114
120
}
121
+
122
+ // There is more, keep looking.
123
+ continue ;
115
124
}
116
125
117
126
let Some ( entry) = find_path_entry_in_commit ( & odb, & suspect, file_path, & mut buf, & mut buf2, & mut stats) ? else {
@@ -162,8 +171,9 @@ where
162
171
// implies that the file comes from a different parent, compared to which
163
172
// it was modified, not added.
164
173
} else {
165
- unblamed_to_out ( & mut hunks_to_blame, & mut out, suspect) ;
166
- break ;
174
+ if unblamed_to_out_is_done ( & mut hunks_to_blame, & mut out, suspect) {
175
+ break ' outer;
176
+ }
167
177
}
168
178
}
169
179
gix_diff:: tree:: recorder:: Change :: Deletion { .. } => {
@@ -209,13 +219,22 @@ fn pass_blame_from_to(from: ObjectId, to: ObjectId, hunks_to_blame: &mut Vec<Unb
209
219
}
210
220
211
221
/// Convert each of the unblamed hunk in `hunks_to_blame` into a [`BlameEntry`], consuming them in the process.
212
- /// `suspect` is expected to be present in the suspect-map in each [`UnblamedHunk`].
213
- fn unblamed_to_out ( hunks_to_blame : & mut Vec < UnblamedHunk > , out : & mut Vec < BlameEntry > , suspect : ObjectId ) {
214
- out. extend (
215
- hunks_to_blame
216
- . drain ( ..)
217
- . map ( |hunk| BlameEntry :: from_unblamed_hunk ( hunk, suspect) ) ,
218
- ) ;
222
+ ///
223
+ /// Return `true` if we are done because `hunks_to_blame` is empty.
224
+ fn unblamed_to_out_is_done (
225
+ hunks_to_blame : & mut Vec < UnblamedHunk > ,
226
+ out : & mut Vec < BlameEntry > ,
227
+ suspect : ObjectId ,
228
+ ) -> bool {
229
+ let mut without_suspect = Vec :: new ( ) ;
230
+ out. extend ( hunks_to_blame. drain ( ..) . filter_map ( |hunk| {
231
+ BlameEntry :: from_unblamed_hunk ( & hunk, suspect) . or_else ( || {
232
+ without_suspect. push ( hunk) ;
233
+ None
234
+ } )
235
+ } ) ) ;
236
+ * hunks_to_blame = without_suspect;
237
+ hunks_to_blame. is_empty ( )
219
238
}
220
239
221
240
/// This function merges adjacent blame entries. It merges entries that are adjacent both in the
0 commit comments