mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-31 13:07:46 +00:00
Merge pull request #5969 from tertsdiepraam/tsort-opt
`tsort`: drastically reduce memory copies
This commit is contained in:
commit
e3c10bcfd3
1 changed files with 34 additions and 37 deletions
|
@ -5,7 +5,7 @@
|
||||||
use clap::{crate_version, Arg, Command};
|
use clap::{crate_version, Arg, Command};
|
||||||
use std::collections::{BTreeMap, BTreeSet};
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{stdin, BufRead, BufReader, Read};
|
use std::io::{stdin, BufReader, Read};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{FromIo, UResult, USimpleError};
|
use uucore::error::{FromIo, UResult, USimpleError};
|
||||||
|
@ -43,31 +43,28 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
&mut file_buf as &mut dyn Read
|
&mut file_buf as &mut dyn Read
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let mut input_buffer = String::new();
|
||||||
|
reader.read_to_string(&mut input_buffer)?;
|
||||||
let mut g = Graph::new();
|
let mut g = Graph::new();
|
||||||
loop {
|
|
||||||
let mut line = String::new();
|
for line in input_buffer.lines() {
|
||||||
match reader.read_line(&mut line) {
|
let tokens: Vec<_> = line.split_whitespace().collect();
|
||||||
Ok(_) => {
|
if tokens.is_empty() {
|
||||||
let tokens: Vec<String> = line.split_whitespace().map(|s| s.to_owned()).collect();
|
break;
|
||||||
if tokens.is_empty() {
|
}
|
||||||
break;
|
for ab in tokens.chunks(2) {
|
||||||
}
|
match ab.len() {
|
||||||
for ab in tokens.chunks(2) {
|
2 => g.add_edge(ab[0], ab[1]),
|
||||||
match ab.len() {
|
_ => {
|
||||||
2 => g.add_edge(&ab[0], &ab[1]),
|
return Err(USimpleError::new(
|
||||||
_ => {
|
1,
|
||||||
return Err(USimpleError::new(
|
format!(
|
||||||
1,
|
"{}: input contains an odd number of tokens",
|
||||||
format!(
|
input.maybe_quote()
|
||||||
"{}: input contains an odd number of tokens",
|
),
|
||||||
input.maybe_quote()
|
))
|
||||||
),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => break,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,13 +101,13 @@ pub fn uu_app() -> Command {
|
||||||
// We use String as a representation of node here
|
// We use String as a representation of node here
|
||||||
// but using integer may improve performance.
|
// but using integer may improve performance.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct Graph {
|
struct Graph<'input> {
|
||||||
in_edges: BTreeMap<String, BTreeSet<String>>,
|
in_edges: BTreeMap<&'input str, BTreeSet<&'input str>>,
|
||||||
out_edges: BTreeMap<String, Vec<String>>,
|
out_edges: BTreeMap<&'input str, Vec<&'input str>>,
|
||||||
result: Vec<String>,
|
result: Vec<&'input str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Graph {
|
impl<'input> Graph<'input> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
@ -123,12 +120,12 @@ impl Graph {
|
||||||
self.in_edges[to].contains(from)
|
self.in_edges[to].contains(from)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_node(&mut self, n: &str) {
|
fn init_node(&mut self, n: &'input str) {
|
||||||
self.in_edges.insert(n.to_string(), BTreeSet::new());
|
self.in_edges.insert(n, BTreeSet::new());
|
||||||
self.out_edges.insert(n.to_string(), vec![]);
|
self.out_edges.insert(n, vec![]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_edge(&mut self, from: &str, to: &str) {
|
fn add_edge(&mut self, from: &'input str, to: &'input str) {
|
||||||
if !self.has_node(to) {
|
if !self.has_node(to) {
|
||||||
self.init_node(to);
|
self.init_node(to);
|
||||||
}
|
}
|
||||||
|
@ -138,8 +135,8 @@ impl Graph {
|
||||||
}
|
}
|
||||||
|
|
||||||
if from != to && !self.has_edge(from, to) {
|
if from != to && !self.has_edge(from, to) {
|
||||||
self.in_edges.get_mut(to).unwrap().insert(from.to_string());
|
self.in_edges.get_mut(to).unwrap().insert(from);
|
||||||
self.out_edges.get_mut(from).unwrap().push(to.to_string());
|
self.out_edges.get_mut(from).unwrap().push(to);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,14 +146,14 @@ impl Graph {
|
||||||
let mut start_nodes = vec![];
|
let mut start_nodes = vec![];
|
||||||
for (n, edges) in &self.in_edges {
|
for (n, edges) in &self.in_edges {
|
||||||
if edges.is_empty() {
|
if edges.is_empty() {
|
||||||
start_nodes.push(n.clone());
|
start_nodes.push(*n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while !start_nodes.is_empty() {
|
while !start_nodes.is_empty() {
|
||||||
let n = start_nodes.remove(0);
|
let n = start_nodes.remove(0);
|
||||||
|
|
||||||
self.result.push(n.clone());
|
self.result.push(n);
|
||||||
|
|
||||||
let n_out_edges = self.out_edges.get_mut(&n).unwrap();
|
let n_out_edges = self.out_edges.get_mut(&n).unwrap();
|
||||||
#[allow(clippy::explicit_iter_loop)]
|
#[allow(clippy::explicit_iter_loop)]
|
||||||
|
@ -166,7 +163,7 @@ impl Graph {
|
||||||
|
|
||||||
// If m doesn't have other in-coming edges add it to start_nodes
|
// If m doesn't have other in-coming edges add it to start_nodes
|
||||||
if m_in_edges.is_empty() {
|
if m_in_edges.is_empty() {
|
||||||
start_nodes.push(m.clone());
|
start_nodes.push(m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
n_out_edges.clear();
|
n_out_edges.clear();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue