about summary refs log tree commit diff
path: root/src/liballoc
diff options
context:
space:
mode:
authorShotaro Yamada <sinkuu@sinkuu.xyz>2018-03-02 13:50:59 +0900
committerShotaro Yamada <sinkuu@sinkuu.xyz>2018-03-02 18:12:22 +0900
commit08504fbb0b05abdd9543f08102b0d6275dde210c (patch)
treeefbfce64f5f77b78f255d2e31027bb2198bfa17b /src/liballoc
parenta85417f5938023d1491b44d94da705f539bb8b17 (diff)
downloadrust-08504fbb0b05abdd9543f08102b0d6275dde210c.tar.gz
rust-08504fbb0b05abdd9543f08102b0d6275dde210c.zip
Optimize str::repeat
Diffstat (limited to 'src/liballoc')
-rw-r--r--src/liballoc/lib.rs1
-rw-r--r--src/liballoc/str.rs37
2 files changed, 35 insertions, 3 deletions
diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs
index d250cfe1880..cb43d5bee78 100644
--- a/src/liballoc/lib.rs
+++ b/src/liballoc/lib.rs
@@ -124,6 +124,7 @@
 #![feature(allocator_internals)]
 #![feature(on_unimplemented)]
 #![feature(exact_chunks)]
+#![feature(pointer_methods)]
 
 #![cfg_attr(not(test), feature(fused, fn_traits, placement_new_protocol, swap_with_slice, i128))]
 #![cfg_attr(test, feature(test, box_heap))]
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.