Skip to content

Commit 95fd0fd

Browse files
committed
Optimize memory allocations
1 parent 49ee1e9 commit 95fd0fd

File tree

1 file changed

+66
-75
lines changed

1 file changed

+66
-75
lines changed

src/lib.rs

Lines changed: 66 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ pub fn glob_with(pattern: &str, options: MatchOptions) -> Result<Paths, PatternE
259259
original: "".to_string(),
260260
tokens: Vec::new(),
261261
is_recursive: false,
262+
is_regular: true,
262263
});
263264
}
264265

@@ -552,6 +553,7 @@ pub struct Pattern {
552553
original: String,
553554
tokens: Vec<PatternToken>,
554555
is_recursive: bool,
556+
is_regular: bool,
555557
}
556558

557559
/// Show the original glob pattern.
@@ -605,11 +607,13 @@ impl Pattern {
605607
let chars = pattern.chars().collect::<Vec<_>>();
606608
let mut tokens = Vec::new();
607609
let mut is_recursive = false;
610+
let mut is_regular = true;
608611
let mut i = 0;
609612

610613
while i < chars.len() {
611614
match chars[i] {
612615
'?' => {
616+
is_regular = false;
613617
tokens.push(AnyChar);
614618
i += 1;
615619
}
@@ -663,10 +667,12 @@ impl Pattern {
663667

664668
if !(tokens_len > 1 && tokens[tokens_len - 1] == AnyRecursiveSequence) {
665669
is_recursive = true;
670+
is_regular = false;
666671
tokens.push(AnyRecursiveSequence);
667672
}
668673
}
669674
} else {
675+
is_regular = false;
670676
tokens.push(AnySequence);
671677
}
672678
}
@@ -678,6 +684,7 @@ impl Pattern {
678684
let chars = &chars[i + 2..i + 3 + j];
679685
let cs = parse_char_specifiers(chars);
680686
tokens.push(AnyExcept(cs));
687+
is_regular = false;
681688
i += j + 4;
682689
continue;
683690
}
@@ -688,6 +695,7 @@ impl Pattern {
688695
Some(j) => {
689696
let cs = parse_char_specifiers(&chars[i + 1..i + 2 + j]);
690697
tokens.push(AnyWithin(cs));
698+
is_regular = false;
691699
i += j + 3;
692700
continue;
693701
}
@@ -711,6 +719,7 @@ impl Pattern {
711719
tokens,
712720
original: pattern.to_string(),
713721
is_recursive,
722+
is_regular,
714723
})
715724
}
716725

@@ -874,19 +883,6 @@ fn fill_todo(
874883
path: &PathWrapper,
875884
options: MatchOptions,
876885
) {
877-
// convert a pattern that's just many Char(_) to a string
878-
fn pattern_as_str(pattern: &Pattern) -> Option<String> {
879-
let mut s = String::new();
880-
for token in &pattern.tokens {
881-
match *token {
882-
Char(c) => s.push(c),
883-
_ => return None,
884-
}
885-
}
886-
887-
Some(s)
888-
}
889-
890886
let add = |todo: &mut Vec<_>, next_path: PathWrapper| {
891887
if idx + 1 == patterns.len() {
892888
// We know it's good, so don't make the iterator match this path
@@ -901,75 +897,70 @@ fn fill_todo(
901897
let pattern = &patterns[idx];
902898
let is_dir = path.is_directory;
903899
let curdir = path.as_ref() == Path::new(".");
904-
match pattern_as_str(pattern) {
905-
Some(s) => {
906-
// This pattern component doesn't have any metacharacters, so we
907-
// don't need to read the current directory to know where to
908-
// continue. So instead of passing control back to the iterator,
909-
// we can just check for that one entry and potentially recurse
910-
// right away.
911-
let special = "." == s || ".." == s;
912-
let next_path = if curdir {
913-
PathBuf::from(s)
914-
} else {
915-
path.join(&s)
916-
};
917-
let next_path = PathWrapper::from_path(next_path);
918-
if (special && is_dir)
919-
|| (!special
920-
&& (fs::metadata(&next_path).is_ok()
921-
|| fs::symlink_metadata(&next_path).is_ok()))
922-
{
923-
add(todo, next_path);
924-
}
900+
if pattern.is_regular {
901+
let s = pattern.as_str();
902+
// This pattern component doesn't have any metacharacters, so we
903+
// don't need to read the current directory to know where to
904+
// continue. So instead of passing control back to the iterator,
905+
// we can just check for that one entry and potentially recurse
906+
// right away.
907+
let special = "." == s || ".." == s;
908+
let next_path = if curdir {
909+
PathBuf::from(s)
910+
} else {
911+
path.join(&s)
912+
};
913+
let next_path = PathWrapper::from_path(next_path);
914+
if (special && is_dir)
915+
|| (!special
916+
&& (fs::metadata(&next_path).is_ok() || fs::symlink_metadata(&next_path).is_ok()))
917+
{
918+
add(todo, next_path);
925919
}
926-
None if is_dir => {
927-
let dirs = fs::read_dir(path).and_then(|d| {
928-
d.map(|e| {
929-
e.map(|e| {
930-
let path = if curdir {
931-
PathBuf::from(e.path().file_name().unwrap())
932-
} else {
933-
e.path()
934-
};
935-
PathWrapper::from_dir_entry(path, e)
936-
})
920+
} else if is_dir {
921+
let dirs = fs::read_dir(path).and_then(|d| {
922+
d.map(|e| {
923+
e.map(|e| {
924+
let path = if curdir {
925+
PathBuf::from(e.path().file_name().unwrap())
926+
} else {
927+
e.path()
928+
};
929+
PathWrapper::from_dir_entry(path, e)
937930
})
938-
.collect::<Result<Vec<_>, _>>()
939-
});
940-
match dirs {
941-
Ok(mut children) => {
942-
if options.require_literal_leading_dot {
943-
children
944-
.retain(|x| !x.file_name().unwrap().to_str().unwrap().starts_with("."));
945-
}
946-
children.sort_by(|p1, p2| p2.file_name().cmp(&p1.file_name()));
947-
todo.extend(children.into_iter().map(|x| Ok((x, idx))));
948-
949-
// Matching the special directory entries . and .. that
950-
// refer to the current and parent directory respectively
951-
// requires that the pattern has a leading dot, even if the
952-
// `MatchOptions` field `require_literal_leading_dot` is not
953-
// set.
954-
if !pattern.tokens.is_empty() && pattern.tokens[0] == Char('.') {
955-
for &special in &[".", ".."] {
956-
if pattern.matches_with(special, options) {
957-
add(todo, PathWrapper::from_path(path.join(special)));
958-
}
931+
})
932+
.collect::<Result<Vec<_>, _>>()
933+
});
934+
match dirs {
935+
Ok(mut children) => {
936+
if options.require_literal_leading_dot {
937+
children.retain(|x| !x.file_name().unwrap().to_str().unwrap().starts_with("."));
938+
}
939+
children.sort_by(|p1, p2| p2.file_name().cmp(&p1.file_name()));
940+
todo.extend(children.into_iter().map(|x| Ok((x, idx))));
941+
942+
// Matching the special directory entries . and .. that
943+
// refer to the current and parent directory respectively
944+
// requires that the pattern has a leading dot, even if the
945+
// `MatchOptions` field `require_literal_leading_dot` is not
946+
// set.
947+
if !pattern.tokens.is_empty() && pattern.tokens[0] == Char('.') {
948+
for &special in &[".", ".."] {
949+
if pattern.matches_with(special, options) {
950+
add(todo, PathWrapper::from_path(path.join(special)));
959951
}
960952
}
961953
}
962-
Err(e) => {
963-
todo.push(Err(GlobError {
964-
path: path.to_path_buf(),
965-
error: e,
966-
}));
967-
}
954+
}
955+
Err(e) => {
956+
todo.push(Err(GlobError {
957+
path: path.to_path_buf(),
958+
error: e,
959+
}));
968960
}
969961
}
970-
None => {
971-
// not a directory, nothing more to find
972-
}
962+
} else {
963+
// not a directory, nothing more to find
973964
}
974965
}
975966

0 commit comments

Comments
 (0)