diff --git a/library/alloctests/tests/str.rs b/library/alloctests/tests/str.rs index 906fa2d425e77..c1642354395fa 100644 --- a/library/alloctests/tests/str.rs +++ b/library/alloctests/tests/str.rs @@ -2357,10 +2357,26 @@ fn utf8_char_counts() { assert!(!target.starts_with(" ") && !target.ends_with(" ")); let expected_count = tmpl_char_count * repeat; + assert_eq!( expected_count, target.chars().count(), - "wrong count for `{:?}.repeat({})` (padding: `{:?}`)", + "wrong count for `{:?}.repeat({}).count()` (padding: `{:?}`)", + tmpl_str, + repeat, + (pad_start.len(), pad_end.len()), + ); + + // `.advance_by(n)` can also be used to count chars. + let mut iter = target.chars(); + let remaining = match iter.advance_by(usize::MAX) { + Ok(()) => 0, + Err(remaining) => remaining.get(), + }; + assert_eq!( + expected_count, + usize::MAX - remaining, + "wrong count for `{:?}.repeat({}).advance_by(usize::MAX)` (padding: `{:?}`)", tmpl_str, repeat, (pad_start.len(), pad_end.len()), diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 425c4eaee28ee..442a13d98aef1 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -200,6 +200,15 @@ impl<'a> Iterator for CharIndices<'a> { self.iter.count() } + #[inline] + fn advance_by(&mut self, remainder: usize) -> Result<(), NonZero> { + let pre_len = self.iter.iter.len(); + let res = self.iter.advance_by(remainder); + let len = self.iter.iter.len(); + self.front_offset += pre_len - len; + res + } + #[inline] fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() diff --git a/library/coretests/benches/str/char_count.rs b/library/coretests/benches/str/char_count.rs index 343e23dcf41c5..3d174a12f26b0 100644 --- a/library/coretests/benches/str/char_count.rs +++ b/library/coretests/benches/str/char_count.rs @@ -48,27 +48,40 @@ macro_rules! define_benches { } define_benches! { - fn case00_libcore(s: &str) { - libcore(s) + fn case00_chars_count(s: &str) { + chars_count(s) } - fn case01_filter_count_cont_bytes(s: &str) { + fn case01_chars_advance_by(s: &str) { + chars_advance_by(s) + } + + fn case02_filter_count_cont_bytes(s: &str) { filter_count_cont_bytes(s) } - fn case02_iter_increment(s: &str) { - iterator_increment(s) + fn case03_iter_chars_increment(s: &str) { + iter_chars_increment(s) } - fn case03_manual_char_len(s: &str) { + fn case04_manual_char_len(s: &str) { manual_char_len(s) } } -fn libcore(s: &str) -> usize { +fn chars_count(s: &str) -> usize { s.chars().count() } +fn chars_advance_by(s: &str) -> usize { + let mut iter = s.chars(); + let remaining = match iter.advance_by(usize::MAX) { + Ok(()) => 0, + Err(remaining) => remaining.get(), + }; + usize::MAX - remaining +} + #[inline] fn utf8_is_cont_byte(byte: u8) -> bool { (byte as i8) < -64 @@ -78,7 +91,7 @@ fn filter_count_cont_bytes(s: &str) -> usize { s.as_bytes().iter().filter(|&&byte| !utf8_is_cont_byte(byte)).count() } -fn iterator_increment(s: &str) -> usize { +fn iter_chars_increment(s: &str) -> usize { let mut c = 0; for _ in s.chars() { c += 1;