Skip to content

Commit f305b02

Browse files
committed
Auto merge of #48999 - GuillaumeGomez:add-repeat-on-slice, r=Kimundi
Add repeat method on slice Fixes #48784.
2 parents a1286f6 + 3c1fea9 commit f305b02

File tree

3 files changed

+91
-53
lines changed

3 files changed

+91
-53
lines changed

src/liballoc/repeat-generic-slice.rs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(repeat_generic_slice)]
12+
13+
fn main() {
14+
assert_eq!([1, 2].repeat(2), vec![1, 2, 1, 2]);
15+
assert_eq!([1, 2, 3, 4].repeat(0), vec![]);
16+
assert_eq!([1, 2, 3, 4].repeat(1), vec![1, 2, 3, 4]);
17+
assert_eq!([1, 2, 3, 4].repeat(3),
18+
vec![1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]);
19+
}

src/liballoc/slice.rs

+71
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,77 @@ impl<T> [T] {
394394
// NB see hack module in this file
395395
hack::into_vec(self)
396396
}
397+
398+
/// Creates a vector by repeating a slice `n` times.
399+
///
400+
/// # Examples
401+
///
402+
/// Basic usage:
403+
///
404+
/// ```
405+
/// #![feature(repeat_generic_slice)]
406+
///
407+
/// fn main() {
408+
/// assert_eq!([1, 2].repeat(3), vec![1, 2, 1, 2, 1, 2]);
409+
/// }
410+
/// ```
411+
#[unstable(feature = "repeat_generic_slice",
412+
reason = "it's on str, why not on slice?",
413+
issue = "48784")]
414+
pub fn repeat(&self, n: usize) -> Vec<T> where T: Copy {
415+
if n == 0 {
416+
return Vec::new();
417+
}
418+
419+
// If `n` is larger than zero, it can be split as
420+
// `n = 2^expn + rem (2^expn > rem, expn >= 0, rem >= 0)`.
421+
// `2^expn` is the number represented by the leftmost '1' bit of `n`,
422+
// and `rem` is the remaining part of `n`.
423+
424+
// Using `Vec` to access `set_len()`.
425+
let mut buf = Vec::with_capacity(self.len() * n);
426+
427+
// `2^expn` repetition is done by doubling `buf` `expn`-times.
428+
buf.extend(self);
429+
{
430+
let mut m = n >> 1;
431+
// If `m > 0`, there are remaining bits up to the leftmost '1'.
432+
while m > 0 {
433+
// `buf.extend(buf)`:
434+
unsafe {
435+
ptr::copy_nonoverlapping(
436+
buf.as_ptr(),
437+
(buf.as_mut_ptr() as *mut T).add(buf.len()),
438+
buf.len(),
439+
);
440+
// `buf` has capacity of `self.len() * n`.
441+
let buf_len = buf.len();
442+
buf.set_len(buf_len * 2);
443+
}
444+
445+
m >>= 1;
446+
}
447+
}
448+
449+
// `rem` (`= n - 2^expn`) repetition is done by copying
450+
// first `rem` repetitions from `buf` itself.
451+
let rem_len = self.len() * n - buf.len(); // `self.len() * rem`
452+
if rem_len > 0 {
453+
// `buf.extend(buf[0 .. rem_len])`:
454+
unsafe {
455+
// This is non-overlapping since `2^expn > rem`.
456+
ptr::copy_nonoverlapping(
457+
buf.as_ptr(),
458+
(buf.as_mut_ptr() as *mut T).add(buf.len()),
459+
rem_len,
460+
);
461+
// `buf.len() + rem_len` equals to `buf.capacity()` (`= self.len() * n`).
462+
let buf_cap = buf.capacity();
463+
buf.set_len(buf_cap);
464+
}
465+
}
466+
buf
467+
}
397468
}
398469

399470
#[cfg_attr(stage0, lang = "slice_u8")]

src/liballoc/str.rs

+1-53
Original file line numberDiff line numberDiff line change
@@ -436,59 +436,7 @@ impl str {
436436
/// ```
437437
#[stable(feature = "repeat_str", since = "1.16.0")]
438438
pub fn repeat(&self, n: usize) -> String {
439-
if n == 0 {
440-
return String::new();
441-
}
442-
443-
// If `n` is larger than zero, it can be split as
444-
// `n = 2^expn + rem (2^expn > rem, expn >= 0, rem >= 0)`.
445-
// `2^expn` is the number represented by the leftmost '1' bit of `n`,
446-
// and `rem` is the remaining part of `n`.
447-
448-
// Using `Vec` to access `set_len()`.
449-
let mut buf = Vec::with_capacity(self.len() * n);
450-
451-
// `2^expn` repetition is done by doubling `buf` `expn`-times.
452-
buf.extend(self.as_bytes());
453-
{
454-
let mut m = n >> 1;
455-
// If `m > 0`, there are remaining bits up to the leftmost '1'.
456-
while m > 0 {
457-
// `buf.extend(buf)`:
458-
unsafe {
459-
ptr::copy_nonoverlapping(
460-
buf.as_ptr(),
461-
(buf.as_mut_ptr() as *mut u8).add(buf.len()),
462-
buf.len(),
463-
);
464-
// `buf` has capacity of `self.len() * n`.
465-
let buf_len = buf.len();
466-
buf.set_len(buf_len * 2);
467-
}
468-
469-
m >>= 1;
470-
}
471-
}
472-
473-
// `rem` (`= n - 2^expn`) repetition is done by copying
474-
// first `rem` repetitions from `buf` itself.
475-
let rem_len = self.len() * n - buf.len(); // `self.len() * rem`
476-
if rem_len > 0 {
477-
// `buf.extend(buf[0 .. rem_len])`:
478-
unsafe {
479-
// This is non-overlapping since `2^expn > rem`.
480-
ptr::copy_nonoverlapping(
481-
buf.as_ptr(),
482-
(buf.as_mut_ptr() as *mut u8).add(buf.len()),
483-
rem_len,
484-
);
485-
// `buf.len() + rem_len` equals to `buf.capacity()` (`= self.len() * n`).
486-
let buf_cap = buf.capacity();
487-
buf.set_len(buf_cap);
488-
}
489-
}
490-
491-
unsafe { String::from_utf8_unchecked(buf) }
439+
unsafe { String::from_utf8_unchecked(self.as_bytes().repeat(n)) }
492440
}
493441

494442
/// Returns a copy of this string where each character is mapped to its

0 commit comments

Comments
 (0)