diff options
| author | Shotaro Yamada <sinkuu@sinkuu.xyz> | 2018-03-02 13:50:59 +0900 |
|---|---|---|
| committer | Shotaro Yamada <sinkuu@sinkuu.xyz> | 2018-03-02 18:12:22 +0900 |
| commit | 08504fbb0b05abdd9543f08102b0d6275dde210c (patch) | |
| tree | efbfce64f5f77b78f255d2e31027bb2198bfa17b /src/liballoc/str.rs | |
| parent | a85417f5938023d1491b44d94da705f539bb8b17 (diff) | |
| download | rust-08504fbb0b05abdd9543f08102b0d6275dde210c.tar.gz rust-08504fbb0b05abdd9543f08102b0d6275dde210c.zip | |
Optimize str::repeat
Diffstat (limited to 'src/liballoc/str.rs')
| -rw-r--r-- | src/liballoc/str.rs | 37 |
1 files changed, 34 insertions, 3 deletions
diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index a00e3d17dd0..08ba4a180ed 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -43,6 +43,7 @@ use core::str as core_str; use core::str::pattern::Pattern; use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; use core::mem; +use core::ptr; use core::iter::FusedIterator; use std_unicode::str::{UnicodeStr, Utf16Encoder}; @@ -2066,9 +2067,39 @@ impl str { /// ``` #[stable(feature = "repeat_str", since = "1.16.0")] pub fn repeat(&self, n: usize) -> String { - let mut s = String::with_capacity(self.len() * n); - s.extend((0..n).map(|_| self)); - s + if n == 0 { + return String::new(); + } + + // n = 2^j + k (2^j > k) + + // 2^j: + let mut s = Vec::with_capacity(self.len() * n); + s.extend(self.as_bytes()); + let mut m = n >> 1; + while m > 0 { + let len = s.len(); + unsafe { + ptr::copy_nonoverlapping(s.as_ptr(), (s.as_mut_ptr() as *mut u8).add(len), len); + s.set_len(len * 2); + } + m >>= 1; + } + + // k: + let res_len = n * self.len(); + if res_len > s.len() { + unsafe { + ptr::copy_nonoverlapping( + s.as_ptr(), + (s.as_mut_ptr() as *mut u8).add(s.len()), + res_len - s.len(), + ); + s.set_len(res_len); + } + } + + unsafe { String::from_utf8_unchecked(s) } } /// Checks if all characters in this string are within the ASCII range. |
