about summary refs log tree commit diff
path: root/src/liballoc/slice.rs
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-04-24 03:31:11 +0000
committerbors <bors@rust-lang.org>2018-04-24 03:31:11 +0000
commitf305b025cf907d0bbdd2135ec59d89cd32e5cbe9 (patch)
tree56355854a989c4b9dcebd7c8576885961d6342ad /src/liballoc/slice.rs
parenta1286f6835ade2d46b936100acd82d44093b3b68 (diff)
parent3c1fea9c0de008d105e8e043b53c4aba57d0df65 (diff)
downloadrust-f305b025cf907d0bbdd2135ec59d89cd32e5cbe9.tar.gz
rust-f305b025cf907d0bbdd2135ec59d89cd32e5cbe9.zip
Auto merge of #48999 - GuillaumeGomez:add-repeat-on-slice, r=Kimundi
Add repeat method on slice

Fixes #48784.
Diffstat (limited to 'src/liballoc/slice.rs')
-rw-r--r--src/liballoc/slice.rs71
1 files changed, 71 insertions, 0 deletions
diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs
index 4594263c01f..d50a3458f20 100644
--- a/src/liballoc/slice.rs
+++ b/src/liballoc/slice.rs
@@ -394,6 +394,77 @@ impl<T> [T] {
         // NB see hack module in this file
         hack::into_vec(self)
     }
+
+    /// Creates a vector by repeating a slice `n` times.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(repeat_generic_slice)]
+    ///
+    /// fn main() {
+    ///     assert_eq!([1, 2].repeat(3), vec![1, 2, 1, 2, 1, 2]);
+    /// }
+    /// ```
+    #[unstable(feature = "repeat_generic_slice",
+               reason = "it's on str, why not on slice?",
+               issue = "48784")]
+    pub fn repeat(&self, n: usize) -> Vec<T> where T: Copy {
+        if n == 0 {
+            return Vec::new();
+        }
+
+        // If `n` is larger than zero, it can be split as
+        // `n = 2^expn + rem (2^expn > rem, expn >= 0, rem >= 0)`.
+        // `2^expn` is the number represented by the leftmost '1' bit of `n`,
+        // and `rem` is the remaining part of `n`.
+
+        // Using `Vec` to access `set_len()`.
+        let mut buf = Vec::with_capacity(self.len() * n);
+
+        // `2^expn` repetition is done by doubling `buf` `expn`-times.
+        buf.extend(self);
+        {
+            let mut m = n >> 1;
+            // If `m > 0`, there are remaining bits up to the leftmost '1'.
+            while m > 0 {
+                // `buf.extend(buf)`:
+                unsafe {
+                    ptr::copy_nonoverlapping(
+                        buf.as_ptr(),
+                        (buf.as_mut_ptr() as *mut T).add(buf.len()),
+                        buf.len(),
+                    );
+                    // `buf` has capacity of `self.len() * n`.
+                    let buf_len = buf.len();
+                    buf.set_len(buf_len * 2);
+                }
+
+                m >>= 1;
+            }
+        }
+
+        // `rem` (`= n - 2^expn`) repetition is done by copying
+        // first `rem` repetitions from `buf` itself.
+        let rem_len = self.len() * n - buf.len(); // `self.len() * rem`
+        if rem_len > 0 {
+            // `buf.extend(buf[0 .. rem_len])`:
+            unsafe {
+                // This is non-overlapping since `2^expn > rem`.
+                ptr::copy_nonoverlapping(
+                    buf.as_ptr(),
+                    (buf.as_mut_ptr() as *mut T).add(buf.len()),
+                    rem_len,
+                );
+                // `buf.len() + rem_len` equals to `buf.capacity()` (`= self.len() * n`).
+                let buf_cap = buf.capacity();
+                buf.set_len(buf_cap);
+            }
+        }
+        buf
+    }
 }
 
 #[cfg_attr(stage0, lang = "slice_u8")]