diff options
| author | bors <bors@rust-lang.org> | 2015-09-14 22:21:41 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2015-09-14 22:21:41 +0000 |
| commit | e629dba0ee190cab49df0c5db299fb8d77264dda (patch) | |
| tree | 7a7414911c1fd6bb6b4c79d9fa059fb20c6159c4 /src/libstd/path.rs | |
| parent | bc6c3970a072ced531f39eaa918084acd43c785a (diff) | |
| parent | 104902100d8894d7578694754590668d6d725a17 (diff) | |
| download | rust-e629dba0ee190cab49df0c5db299fb8d77264dda.tar.gz rust-e629dba0ee190cab49df0c5db299fb8d77264dda.zip | |
Auto merge of #28256 - petrochenkov:conv, r=alexcrichton
This patch transforms functions of the form
```
fn f<Generic: AsRef<Concrete>>(arg: Generic) {
let arg: &Concrete = arg.as_ref();
// Code using arg
}
```
to the next form:
```
#[inline]
fn f<Generic: AsRef<Concrete>>(arg: Generic) {
fn f_inner(arg: &Concrete) {
// Code using arg
}
f_inner(arg.as_ref());
}
```
Therefore, most of the code is concrete and not duplicated during monomorphisation (unless inlined)
and only the tiny bit of conversion code is duplicated. This method was mentioned by @aturon in the
Conversion Traits RFC (https://github.com/rust-lang/rfcs/blame/master/text/0529-conversion-traits.md#L249) and similar techniques are not uncommon in C++ template libraries.
This patch goes to the extremes and applies the transformation even to smaller functions<sup>1</sup>
for purity of the experiment. *Some of them can be rolled back* if considered too ridiculous.
<sup>1</sup> However who knows how small are these functions are after inlining and everything.
The functions in question are mostly `fs`/`os` functions and not used especially often with variety
of argument types, so the code size reduction is rather small (but consistent). Here are the sizes
of stage2 artifacts before and after the patch:
https://gist.github.com/petrochenkov/e76a6b280f382da13c5d
https://gist.github.com/petrochenkov/6cc28727d5256dbdfed0
Note:
All the `inner` functions are concrete and unavailable for cross-crate inlining, some of them may
need `#[inline]` annotations in the future.
r? @aturon
Diffstat (limited to 'src/libstd/path.rs')
| -rw-r--r-- | src/libstd/path.rs | 47 |
1 files changed, 40 insertions, 7 deletions
diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 66893ffd330..8eb5d1f2726 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -965,8 +965,10 @@ impl PathBuf { /// * if `path` has a prefix but no root, it replaces `self`. #[stable(feature = "rust1", since = "1.0.0")] pub fn push<P: AsRef<Path>>(&mut self, path: P) { - let path = path.as_ref(); + self._push(path.as_ref()) + } + fn _push(&mut self, path: &Path) { // in general, a separator is needed if the rightmost byte is not a separator let mut need_sep = self.as_mut_vec().last().map(|c| !is_sep_byte(*c)).unwrap_or(false); @@ -1033,11 +1035,15 @@ impl PathBuf { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn set_file_name<S: AsRef<OsStr>>(&mut self, file_name: S) { + self._set_file_name(file_name.as_ref()) + } + + fn _set_file_name(&mut self, file_name: &OsStr) { if self.file_name().is_some() { let popped = self.pop(); debug_assert!(popped); } - self.push(file_name.as_ref()); + self.push(file_name); } /// Updates `self.extension()` to `extension`. @@ -1048,6 +1054,10 @@ impl PathBuf { /// is added; otherwise it is replaced. #[stable(feature = "rust1", since = "1.0.0")] pub fn set_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool { + self._set_extension(extension.as_ref()) + } + + fn _set_extension(&mut self, extension: &OsStr) -> bool { if self.file_name().is_none() { return false; } let mut stem = match self.file_stem() { @@ -1055,7 +1065,6 @@ impl PathBuf { None => OsString::new(), }; - let extension = extension.as_ref(); if !os_str_as_u8_slice(extension).is_empty() { stem.push("."); stem.push(extension); @@ -1106,7 +1115,7 @@ impl<P: AsRef<Path>> iter::FromIterator<P> for PathBuf { impl<P: AsRef<Path>> iter::Extend<P> for PathBuf { fn extend<I: IntoIterator<Item = P>>(&mut self, iter: I) { for p in iter { - self.push(p) + self.push(p.as_ref()) } } } @@ -1452,7 +1461,11 @@ impl Path { issue = "23284")] pub fn relative_from<'a, P: ?Sized + AsRef<Path>>(&'a self, base: &'a P) -> Option<&Path> { - iter_after(self.components(), base.as_ref().components()).map(|c| c.as_path()) + self._relative_from(base.as_ref()) + } + + fn _relative_from<'a>(&'a self, base: &'a Path) -> Option<&'a Path> { + iter_after(self.components(), base.components()).map(|c| c.as_path()) } /// Determines whether `base` is a prefix of `self`. @@ -1472,7 +1485,11 @@ impl Path { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn starts_with<P: AsRef<Path>>(&self, base: P) -> bool { - iter_after(self.components(), base.as_ref().components()).is_some() + self._starts_with(base.as_ref()) + } + + fn _starts_with(&self, base: &Path) -> bool { + iter_after(self.components(), base.components()).is_some() } /// Determines whether `child` is a suffix of `self`. @@ -1490,7 +1507,11 @@ impl Path { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn ends_with<P: AsRef<Path>>(&self, child: P) -> bool { - iter_after(self.components().rev(), child.as_ref().components().rev()).is_some() + self._ends_with(child.as_ref()) + } + + fn _ends_with(&self, child: &Path) -> bool { + iter_after(self.components().rev(), child.components().rev()).is_some() } /// Extracts the stem (non-extension) portion of `self.file_name()`. @@ -1552,6 +1573,10 @@ impl Path { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn join<P: AsRef<Path>>(&self, path: P) -> PathBuf { + self._join(path.as_ref()) + } + + fn _join(&self, path: &Path) -> PathBuf { let mut buf = self.to_path_buf(); buf.push(path); buf @@ -1571,6 +1596,10 @@ impl Path { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_file_name<S: AsRef<OsStr>>(&self, file_name: S) -> PathBuf { + self._with_file_name(file_name.as_ref()) + } + + fn _with_file_name(&self, file_name: &OsStr) -> PathBuf { let mut buf = self.to_path_buf(); buf.set_file_name(file_name); buf @@ -1590,6 +1619,10 @@ impl Path { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf { + self._with_extension(extension.as_ref()) + } + + fn _with_extension(&self, extension: &OsStr) -> PathBuf { let mut buf = self.to_path_buf(); buf.set_extension(extension); buf |
