use super::shared::Shared;
use cpu::fence_release;
use std::sync::Arc;
pub struct BatchSlots<'a, T> {
pub(super) shared: &'a Arc<Shared<T>>,
pub(super) start: i64,
pub(super) count: usize,
pub(super) published: bool,
}
impl<'a, T> BatchSlots<'a, T> {
#[inline]
pub fn get_mut(&mut self, index: usize) -> &mut T {
assert!(
index < self.count,
"index {} out of bounds for batch of {}",
index,
self.count
);
unsafe { self.shared.buffer.get_mut(self.start + index as i64) }
}
#[inline]
pub fn get(&self, index: usize) -> &T {
assert!(
index < self.count,
"index {} out of bounds for batch of {}",
index,
self.count
);
unsafe { self.shared.buffer.get(self.start + index as i64) }
}
#[inline]
pub fn len(&self) -> usize {
self.count
}
#[inline]
pub fn is_empty(&self) -> bool {
self.count == 0
}
#[inline]
pub fn publish(mut self) {
self.do_publish();
}
#[inline]
pub(super) fn do_publish(&mut self) {
if !self.published {
fence_release();
self.shared
.producer_cursor
.set_relaxed(self.start + self.count as i64 - 1);
self.published = true;
}
}
#[inline]
pub fn iter_mut(&mut self) -> BatchSlotIterMut<'_, T> {
BatchSlotIterMut {
shared: self.shared,
current: self.start,
end: self.start + self.count as i64,
}
}
}
impl<'a, T> Drop for BatchSlots<'a, T> {
fn drop(&mut self) {
self.do_publish();
}
}
pub struct BatchSlotIterMut<'a, T> {
shared: &'a Arc<Shared<T>>,
current: i64,
end: i64,
}
impl<'a, T> Iterator for BatchSlotIterMut<'a, T> {
type Item = &'a mut T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.current < self.end {
let seq = self.current;
self.current += 1;
Some(unsafe { &mut *self.shared.buffer.get_ptr_mut(seq) })
} else {
None
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = (self.end - self.current) as usize;
(remaining, Some(remaining))
}
}
impl<'a, T> ExactSizeIterator for BatchSlotIterMut<'a, T> {}