Skip to content

Commit f72446c

Browse files
committed
A few optimizations
1 parent 8b16ba3 commit f72446c

File tree

1 file changed

+58
-41
lines changed

1 file changed

+58
-41
lines changed

src/chunks.rs

Lines changed: 58 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -349,14 +349,13 @@ where
349349
{
350350
/// Fills all slots with the [`Default`] value.
351351
fn from(chunk: WriteChunkUninit<'a, T>) -> Self {
352-
for slot in chunk
353-
.first_slice
354-
.iter_mut()
355-
.chain(chunk.second_slice.iter_mut())
356-
{
357-
unsafe {
358-
slot.as_mut_ptr().write(Default::default());
359-
}
352+
// NB: Using Iterator::chain() to iterate over both slices
353+
// led to worse optimization (with rustc 1.57).
354+
for slot in chunk.first_slice.iter_mut() {
355+
*slot = MaybeUninit::new(Default::default());
356+
}
357+
for slot in chunk.second_slice.iter_mut() {
358+
*slot = MaybeUninit::new(Default::default());
360359
}
361360
WriteChunk(Some(chunk))
362361
}
@@ -558,18 +557,33 @@ impl<T> WriteChunkUninit<'_, T> {
558557
where
559558
I: IntoIterator<Item = T>,
560559
{
561-
let iterated = self
562-
.first_slice
563-
.iter_mut()
564-
.chain(self.second_slice.iter_mut())
565-
.zip(iter)
566-
.map(|(slot, item)| {
567-
// Safety: It is allowed to write to this memory slot
568-
unsafe {
569-
slot.as_mut_ptr().write(item);
560+
let mut iter = iter.into_iter();
561+
let mut iterated = 0;
562+
// NB: Iterating over slices (instead of using pointers)
563+
// led to worse optimization (with rustc 1.57).
564+
'outer: for &(ptr, len) in &[
565+
(
566+
self.first_slice.as_mut_ptr().cast::<T>(),
567+
self.first_slice.len(),
568+
),
569+
(
570+
self.second_slice.as_mut_ptr().cast::<T>(),
571+
self.second_slice.len(),
572+
),
573+
] {
574+
for i in 0..len {
575+
match iter.next() {
576+
Some(item) => {
577+
// Safety: It is allowed to write to this memory slot
578+
unsafe {
579+
ptr.add(i).write(item);
580+
}
581+
iterated += 1;
582+
}
583+
None => break 'outer,
570584
}
571-
})
572-
.count();
585+
}
586+
}
573587
// Safety: iterated slots have been initialized above
574588
unsafe { self.commit_unchecked(iterated) }
575589
}
@@ -713,14 +727,13 @@ impl<T> ReadChunk<'_, T> {
713727
}
714728

715729
unsafe fn commit_unchecked(self, n: usize) -> usize {
716-
for slot in self
717-
.first_slice
730+
self.first_slice
718731
.iter_mut()
719732
.chain(self.second_slice.iter_mut())
720733
.take(n)
721-
{
722-
slot.as_mut_ptr().drop_in_place();
723-
}
734+
.for_each(|slot| {
735+
slot.as_mut_ptr().drop_in_place();
736+
});
724737
let c = self.consumer;
725738
let head = c.buffer().increment(c.cached_head.get(), n);
726739
c.buffer().head.store(head, Ordering::Release);
@@ -751,12 +764,8 @@ impl<'a, T> IntoIterator for ReadChunk<'a, T> {
751764
/// Non-iterated items remain in the ring buffer.
752765
fn into_iter(self) -> Self::IntoIter {
753766
Self::IntoIter {
754-
chunk_size: self.len(),
755-
iter: self
756-
.first_slice
757-
.iter_mut()
758-
.chain(self.second_slice.iter_mut()),
759-
consumer: self.consumer,
767+
chunk: self,
768+
iterated: 0,
760769
}
761770
}
762771
}
@@ -770,22 +779,17 @@ impl<'a, T> IntoIterator for ReadChunk<'a, T> {
770779
/// Non-iterated items remain in the ring buffer.
771780
#[derive(Debug)]
772781
pub struct ReadChunkIntoIter<'a, T> {
773-
chunk_size: usize,
774-
iter: core::iter::Chain<
775-
core::slice::IterMut<'a, MaybeUninit<T>>,
776-
core::slice::IterMut<'a, MaybeUninit<T>>,
777-
>,
778-
consumer: &'a mut Consumer<T>,
782+
chunk: ReadChunk<'a, T>,
783+
iterated: usize,
779784
}
780785

781786
impl<'a, T> Drop for ReadChunkIntoIter<'a, T> {
782787
/// Makes all iterated slots available for writing again.
783788
///
784789
/// Non-iterated items remain in the ring buffer and are *not* dropped.
785790
fn drop(&mut self) {
786-
let iterated = self.chunk_size - self.len();
787-
let c = &self.consumer;
788-
let head = c.buffer().increment(c.cached_head.get(), iterated);
791+
let c = &self.chunk.consumer;
792+
let head = c.buffer().increment(c.cached_head.get(), self.iterated);
789793
c.buffer().head.store(head, Ordering::Release);
790794
c.cached_head.set(head);
791795
}
@@ -795,11 +799,24 @@ impl<'a, T> Iterator for ReadChunkIntoIter<'a, T> {
795799
type Item = T;
796800

797801
fn next(&mut self) -> Option<Self::Item> {
798-
self.iter.next().map(|slot| unsafe { slot.as_ptr().read() })
802+
self.chunk
803+
.first_slice
804+
.get(self.iterated)
805+
.or_else(|| {
806+
self.chunk
807+
.second_slice
808+
.get(self.iterated - self.chunk.first_slice.len())
809+
})
810+
.map(|slot| unsafe { slot.as_ptr().read() })
811+
.map(|item| {
812+
self.iterated += 1;
813+
item
814+
})
799815
}
800816

801817
fn size_hint(&self) -> (usize, Option<usize>) {
802-
self.iter.size_hint()
818+
let size = self.chunk.first_slice.len() + self.chunk.second_slice.len() - self.iterated;
819+
(size, Some(size))
803820
}
804821
}
805822

0 commit comments

Comments
 (0)