Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions library/std/benches/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,30 @@ fn bench_path_cmp_fast_path_short(b: &mut test::Bencher) {
});
}

#[bench]
fn bench_path_components_iter(b: &mut test::Bencher) {
let p = Path::new("/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/");

b.iter(|| {
for c in black_box(p).components() {
black_box(c);
}
})
}

#[bench]
fn bench_path_file_name(b: &mut test::Bencher) {
let p1 = Path::new("foo.bar");
let p2 = Path::new("foo/bar");
let p3 = Path::new("/bar");

b.iter(|| {
black_box(black_box(p1).file_name());
black_box(black_box(p2).file_name());
black_box(black_box(p3).file_name());
})
}

#[bench]
#[cfg_attr(miri, ignore)] // Miri isn't fast...
fn bench_path_hashset(b: &mut test::Bencher) {
Expand Down
74 changes: 44 additions & 30 deletions library/std/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ use crate::ops::{self, Deref};
use crate::rc::Rc;
use crate::str::FromStr;
use crate::sync::Arc;
use crate::sys::path::{MAIN_SEP_STR, is_sep_byte, is_verbatim_sep, parse_prefix};
use crate::sys::path::{HAS_PREFIXES, MAIN_SEP_STR, is_sep_byte, is_verbatim_sep, parse_prefix};
use crate::{cmp, fmt, fs, io, sys};

////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -643,17 +643,26 @@ impl<'a> Components<'a> {
// how long is the prefix, if any?
#[inline]
fn prefix_len(&self) -> usize {
if !HAS_PREFIXES {
return 0;
}
self.prefix.as_ref().map(Prefix::len).unwrap_or(0)
}

#[inline]
fn prefix_verbatim(&self) -> bool {
if !HAS_PREFIXES {
return false;
}
self.prefix.as_ref().map(Prefix::is_verbatim).unwrap_or(false)
}

/// how much of the prefix is left from the point of view of iteration?
#[inline]
fn prefix_remaining(&self) -> usize {
if !HAS_PREFIXES {
return 0;
}
if self.front == State::Prefix { self.prefix_len() } else { 0 }
}

Expand Down Expand Up @@ -707,7 +716,7 @@ impl<'a> Components<'a> {
if self.has_physical_root {
return true;
}
if let Some(p) = self.prefix {
if HAS_PREFIXES && let Some(p) = self.prefix {
if p.has_implicit_root() {
return true;
}
Expand All @@ -720,10 +729,10 @@ impl<'a> Components<'a> {
if self.has_root() {
return false;
}
let mut iter = self.path[self.prefix_remaining()..].iter();
match (iter.next(), iter.next()) {
(Some(&b'.'), None) => true,
(Some(&b'.'), Some(&b)) => self.is_sep_byte(b),
let slice = &self.path[self.prefix_remaining()..];
match slice {
[b'.'] => true,
[b'.', b, ..] => self.is_sep_byte(*b),
_ => false,
}
}
Expand All @@ -732,7 +741,7 @@ impl<'a> Components<'a> {
// corresponding path component
unsafe fn parse_single_component<'b>(&self, comp: &'b [u8]) -> Option<Component<'b>> {
match comp {
b"." if self.prefix_verbatim() => Some(Component::CurDir),
b"." if HAS_PREFIXES && self.prefix_verbatim() => Some(Component::CurDir),
b"." => None, // . components are normalized away, except at
// the beginning of a path, which is treated
// separately via `include_cur_dir`
Expand Down Expand Up @@ -889,26 +898,24 @@ impl<'a> Iterator for Components<'a> {
fn next(&mut self) -> Option<Component<'a>> {
while !self.finished() {
match self.front {
State::Prefix if self.prefix_len() > 0 => {
self.front = State::StartDir;
debug_assert!(self.prefix_len() <= self.path.len());
let raw = &self.path[..self.prefix_len()];
self.path = &self.path[self.prefix_len()..];
return Some(Component::Prefix(PrefixComponent {
raw: unsafe { OsStr::from_encoded_bytes_unchecked(raw) },
parsed: self.prefix.unwrap(),
}));
// most likely case first
State::Body if !self.path.is_empty() => {
let (size, comp) = self.parse_next_component();
self.path = &self.path[size..];
if comp.is_some() {
return comp;
}
}
State::Prefix => {
self.front = State::StartDir;
State::Body => {
self.front = State::Done;
}
State::StartDir => {
self.front = State::Body;
if self.has_physical_root {
debug_assert!(!self.path.is_empty());
self.path = &self.path[1..];
return Some(Component::RootDir);
} else if let Some(p) = self.prefix {
} else if HAS_PREFIXES && let Some(p) = self.prefix {
if p.has_implicit_root() && !p.is_verbatim() {
return Some(Component::RootDir);
}
Expand All @@ -918,15 +925,19 @@ impl<'a> Iterator for Components<'a> {
return Some(Component::CurDir);
}
}
State::Body if !self.path.is_empty() => {
let (size, comp) = self.parse_next_component();
self.path = &self.path[size..];
if comp.is_some() {
return comp;
}
_ if const { !HAS_PREFIXES } => unreachable!(),
State::Prefix if self.prefix_len() == 0 => {
self.front = State::StartDir;
}
State::Body => {
self.front = State::Done;
State::Prefix => {
self.front = State::StartDir;
debug_assert!(self.prefix_len() <= self.path.len());
let raw = &self.path[..self.prefix_len()];
self.path = &self.path[self.prefix_len()..];
return Some(Component::Prefix(PrefixComponent {
raw: unsafe { OsStr::from_encoded_bytes_unchecked(raw) },
parsed: self.prefix.unwrap(),
}));
}
State::Done => unreachable!(),
}
Expand All @@ -951,11 +962,11 @@ impl<'a> DoubleEndedIterator for Components<'a> {
self.back = State::StartDir;
}
State::StartDir => {
self.back = State::Prefix;
self.back = if HAS_PREFIXES { State::Prefix } else { State::Done };
if self.has_physical_root {
self.path = &self.path[..self.path.len() - 1];
return Some(Component::RootDir);
} else if let Some(p) = self.prefix {
} else if HAS_PREFIXES && let Some(p) = self.prefix {
if p.has_implicit_root() && !p.is_verbatim() {
return Some(Component::RootDir);
}
Expand All @@ -964,6 +975,7 @@ impl<'a> DoubleEndedIterator for Components<'a> {
return Some(Component::CurDir);
}
}
_ if !HAS_PREFIXES => unreachable!(),
State::Prefix if self.prefix_len() > 0 => {
self.back = State::Done;
return Some(Component::Prefix(PrefixComponent {
Expand Down Expand Up @@ -3116,7 +3128,9 @@ impl Path {
path: self.as_u8_slice(),
prefix,
has_physical_root: has_physical_root(self.as_u8_slice(), prefix),
front: State::Prefix,
// use a platform-specific initial state to avoid one turn of
// the state-machine when the platform doesn't have a Prefix.
front: const { if HAS_PREFIXES { State::Prefix } else { State::StartDir } },
back: State::Body,
}
}
Expand Down
1 change: 1 addition & 0 deletions library/std/src/sys/path/cygwin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub fn is_verbatim_sep(b: u8) -> bool {

pub use super::windows_prefix::parse_prefix;

pub const HAS_PREFIXES: bool = true;
pub const MAIN_SEP_STR: &str = "/";
pub const MAIN_SEP: char = '/';

Expand Down
1 change: 1 addition & 0 deletions library/std/src/sys/path/sgx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
None
}

pub const HAS_PREFIXES: bool = false;
pub const MAIN_SEP_STR: &str = "/";
pub const MAIN_SEP: char = '/';

Expand Down
1 change: 1 addition & 0 deletions library/std/src/sys/path/uefi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
None
}

pub const HAS_PREFIXES: bool = true;
pub const MAIN_SEP_STR: &str = "\\";
pub const MAIN_SEP: char = '\\';

Expand Down
1 change: 1 addition & 0 deletions library/std/src/sys/path/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
None
}

pub const HAS_PREFIXES: bool = false;
pub const MAIN_SEP_STR: &str = "/";
pub const MAIN_SEP: char = '/';

Expand Down
1 change: 1 addition & 0 deletions library/std/src/sys/path/unsupported_backslash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
None
}

pub const HAS_PREFIXES: bool = true;
pub const MAIN_SEP_STR: &str = "\\";
pub const MAIN_SEP: char = '\\';

Expand Down
1 change: 1 addition & 0 deletions library/std/src/sys/path/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ mod tests;

pub use super::windows_prefix::parse_prefix;

pub const HAS_PREFIXES: bool = true;
pub const MAIN_SEP_STR: &str = "\\";
pub const MAIN_SEP: char = '\\';

Expand Down
Loading