From dc4deaeb767fddba95ade0d4fd7c6f5d1b23d02b Mon Sep 17 00:00:00 2001 From: Psilon Date: Thu, 30 Jan 2025 14:54:57 +0200 Subject: [PATCH 1/3] add from iterator impl --- src/array_string.rs | 30 ++++++++++++++++++++++++++++++ tests/tests.rs | 25 +++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/src/array_string.rs b/src/array_string.rs index 227e01d..922d924 100644 --- a/src/array_string.rs +++ b/src/array_string.rs @@ -295,6 +295,36 @@ impl ArrayString Ok(()) } + pub fn try_push_iterator>(&mut self, value: I) -> Result<(), CapacityError<()>> { + let mut len = self.len(); + let value = value.into_iter(); + if value.size_hint().0 > self.capacity() - len { + return Err(CapacityError::new(())); + } + + unsafe { + let mut ptr = self.as_mut_ptr().add(self.len()); + for c in value { + let remaining_cap = self.capacity() - len; + match encode_utf8(c, ptr, remaining_cap) { + Ok(n) => { + len += n; + ptr = ptr.add(n); + } + Err(_) => return Err(CapacityError::new(())), + } + } + self.set_len(len); + Ok(()) + } + } + + pub fn try_from_iterator>(value: I) -> Result> { + let mut string = Self::new(); + string.try_push_iterator(value)?; + Ok(string) + } + /// Removes the last character from the string and returns it. /// /// Returns `None` if this `ArrayString` is empty. diff --git a/tests/tests.rs b/tests/tests.rs index ff779ba..03fb4f8 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -774,3 +774,28 @@ fn test_arraystring_zero_filled_has_some_sanity_checks() { assert_eq!(string.as_str(), "\0\0\0\0"); assert_eq!(string.len(), 4); } + +#[test] +fn test_string_collect() { + let text = "hello world"; + let u = ArrayString::<11>::try_from_iterator(text.chars()).unwrap(); + assert_eq!(u.as_str(), text); + assert_eq!(u.len(), text.len()); +} + +#[test] +fn test_string_collect_seveal_times() { + let text = "hello world"; + let mut u = ArrayString::<22>::try_from_iterator(text.chars()).unwrap(); + u.try_push_iterator(text.chars()).unwrap(); + assert_eq!(u.as_str(), &format!("{}{}", text, text)); + assert_eq!(u.len(), text.len()*2); +} + + +#[test] +fn test_string_collect_error_on_overflow() { + let text = "hello world"; + ArrayString::<10>::try_from_iterator(text.chars()).unwrap_err(); +} + From 9dac45f2d7fac307b2d1772708ce318bb1cdffe2 Mon Sep 17 00:00:00 2001 From: Psilon Date: Sat, 1 Feb 2025 11:35:03 +0200 Subject: [PATCH 2/3] rename try_extend method --- src/array_string.rs | 4 ++-- tests/tests.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/array_string.rs b/src/array_string.rs index 922d924..09784ee 100644 --- a/src/array_string.rs +++ b/src/array_string.rs @@ -295,7 +295,7 @@ impl ArrayString Ok(()) } - pub fn try_push_iterator>(&mut self, value: I) -> Result<(), CapacityError<()>> { + pub fn try_extend>(&mut self, value: I) -> Result<(), CapacityError<()>> { let mut len = self.len(); let value = value.into_iter(); if value.size_hint().0 > self.capacity() - len { @@ -321,7 +321,7 @@ impl ArrayString pub fn try_from_iterator>(value: I) -> Result> { let mut string = Self::new(); - string.try_push_iterator(value)?; + string.try_extend(value)?; Ok(string) } diff --git a/tests/tests.rs b/tests/tests.rs index 03fb4f8..e979759 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -787,7 +787,7 @@ fn test_string_collect() { fn test_string_collect_seveal_times() { let text = "hello world"; let mut u = ArrayString::<22>::try_from_iterator(text.chars()).unwrap(); - u.try_push_iterator(text.chars()).unwrap(); + u.try_extend(text.chars()).unwrap(); assert_eq!(u.as_str(), &format!("{}{}", text, text)); assert_eq!(u.len(), text.len()*2); } From 8eabdf507a821332900a11d3e0e1f71a459bbd3e Mon Sep 17 00:00:00 2001 From: Psilon Date: Sat, 1 Feb 2025 13:01:11 +0200 Subject: [PATCH 3/3] benches & fix existing ones --- benches/arraystring.rs | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/benches/arraystring.rs b/benches/arraystring.rs index 5b986fa..8bf5786 100644 --- a/benches/arraystring.rs +++ b/benches/arraystring.rs @@ -12,7 +12,7 @@ fn try_push_c(b: &mut Bencher) { v.clear(); while v.try_push('c').is_ok() { } - v.len() + std::hint::black_box(v) }); b.bytes = v.capacity() as u64; } @@ -23,7 +23,7 @@ fn try_push_alpha(b: &mut Bencher) { v.clear(); while v.try_push('α').is_ok() { } - v.len() + std::hint::black_box(v) }); b.bytes = v.capacity() as u64; } @@ -39,7 +39,7 @@ fn try_push_string(b: &mut Bencher) { break; } } - v.len() + std::hint::black_box(v) }); b.bytes = v.capacity() as u64; } @@ -51,7 +51,7 @@ fn push_c(b: &mut Bencher) { while !v.is_full() { v.push('c'); } - v.len() + std::hint::black_box(v) }); b.bytes = v.capacity() as u64; } @@ -63,7 +63,7 @@ fn push_alpha(b: &mut Bencher) { while !v.is_full() { v.push('α'); } - v.len() + std::hint::black_box(v) }); b.bytes = v.capacity() as u64; } @@ -80,11 +80,37 @@ fn push_string(b: &mut Bencher) { break; } } - v.len() + std::hint::black_box(v) + }); + b.bytes = v.capacity() as u64; +} + +fn try_extend_bench(b: &mut Bencher) { + let mut v = ArrayString::<4096>::new(); + b.iter(|| { + v.clear(); + + v.try_extend(std::iter::repeat('a').take(v.capacity())).unwrap(); + + std::hint::black_box(v); + }); + b.bytes = v.capacity() as u64; +} + +fn try_push_loop(b: &mut Bencher) { + let mut v = ArrayString::<4096>::new(); + b.iter(|| { + v.clear(); + + for c in std::iter::repeat('a').take(v.capacity()) { + v.try_push(c).unwrap(); + } + + std::hint::black_box(v) }); b.bytes = v.capacity() as u64; } benchmark_group!(benches, try_push_c, try_push_alpha, try_push_string, push_c, - push_alpha, push_string); + push_alpha, push_string, try_extend_bench, try_push_loop); benchmark_main!(benches);