Skip to content

Commit 9a3c162

Browse files
committed
Auto merge of #9586 - tmiasko:lines, r=alexcrichton
Avoid quadratic complexity when splitting output into lines When searching for newlines in a process output keep track which part of buffer was already examined to avoid processing the same data again and again.
2 parents af6d540 + 8df771f commit 9a3c162

File tree

1 file changed

+33
-26
lines changed

1 file changed

+33
-26
lines changed

crates/cargo-util/src/process_builder.rs

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -243,47 +243,54 @@ impl ProcessBuilder {
243243
.stdin(Stdio::null());
244244

245245
let mut callback_error = None;
246+
let mut stdout_pos = 0;
247+
let mut stderr_pos = 0;
246248
let status = (|| {
247249
let mut child = cmd.spawn()?;
248250
let out = child.stdout.take().unwrap();
249251
let err = child.stderr.take().unwrap();
250252
read2(out, err, &mut |is_out, data, eof| {
253+
let pos = if is_out {
254+
&mut stdout_pos
255+
} else {
256+
&mut stderr_pos
257+
};
251258
let idx = if eof {
252259
data.len()
253260
} else {
254-
match data.iter().rposition(|b| *b == b'\n') {
255-
Some(i) => i + 1,
256-
None => return,
261+
match data[*pos..].iter().rposition(|b| *b == b'\n') {
262+
Some(i) => *pos + i + 1,
263+
None => {
264+
*pos = data.len();
265+
return;
266+
}
257267
}
258268
};
259-
{
260-
// scope for new_lines
261-
let new_lines = if capture_output {
262-
let dst = if is_out { &mut stdout } else { &mut stderr };
263-
let start = dst.len();
264-
let data = data.drain(..idx);
265-
dst.extend(data);
266-
&dst[start..]
269+
270+
let new_lines = &data[..idx];
271+
272+
for line in String::from_utf8_lossy(new_lines).lines() {
273+
if callback_error.is_some() {
274+
break;
275+
}
276+
let callback_result = if is_out {
277+
on_stdout_line(line)
267278
} else {
268-
&data[..idx]
279+
on_stderr_line(line)
269280
};
270-
for line in String::from_utf8_lossy(new_lines).lines() {
271-
if callback_error.is_some() {
272-
break;
273-
}
274-
let callback_result = if is_out {
275-
on_stdout_line(line)
276-
} else {
277-
on_stderr_line(line)
278-
};
279-
if let Err(e) = callback_result {
280-
callback_error = Some(e);
281-
}
281+
if let Err(e) = callback_result {
282+
callback_error = Some(e);
283+
break;
282284
}
283285
}
284-
if !capture_output {
285-
data.drain(..idx);
286+
287+
if capture_output {
288+
let dst = if is_out { &mut stdout } else { &mut stderr };
289+
dst.extend(new_lines);
286290
}
291+
292+
data.drain(..idx);
293+
*pos = 0;
287294
})?;
288295
child.wait()
289296
})()

0 commit comments

Comments
 (0)