use crate::MiniVec;
extern crate alloc;
pub struct Splice<'a, I>
where
I: 'a + Iterator,
{
vec_: core::ptr::NonNull<MiniVec<I::Item>>,
drain_pos_: core::ptr::NonNull<I::Item>,
drain_end_: core::ptr::NonNull<I::Item>,
remaining_pos_: core::ptr::NonNull<I::Item>,
remaining_: usize,
marker_: core::marker::PhantomData<&'a I::Item>,
fill_: I,
}
pub fn make_splice_iterator<'a, I: 'a + Iterator>(
vec: &mut MiniVec<I::Item>,
data: *mut I::Item,
remaining: usize,
start_idx: usize,
end_idx: usize,
fill: I,
) -> Splice<'a, I> {
if data.is_null() {
let dangling = core::ptr::NonNull::<I::Item>::dangling();
Splice {
vec_: core::ptr::NonNull::from(vec),
drain_pos_: dangling,
drain_end_: dangling,
remaining_pos_: dangling,
remaining_: 0,
marker_: core::marker::PhantomData,
fill_: fill,
}
} else {
Splice {
vec_: core::ptr::NonNull::from(vec),
drain_pos_: unsafe { core::ptr::NonNull::new_unchecked(data.add(start_idx)) },
drain_end_: unsafe { core::ptr::NonNull::new_unchecked(data.add(end_idx)) },
remaining_pos_: unsafe { core::ptr::NonNull::new_unchecked(data.add(end_idx)) },
remaining_: remaining,
marker_: core::marker::PhantomData,
fill_: fill,
}
}
}
impl<I> Iterator for Splice<'_, I>
where
I: Iterator,
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
if self.drain_pos_ >= self.drain_end_ {
return None;
}
let p = self.drain_pos_.as_ptr();
let tmp = unsafe { core::ptr::read(p) };
self.drain_pos_ = unsafe { core::ptr::NonNull::new_unchecked(p.add(1)) };
Some(tmp)
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = (self.drain_end_.as_ptr() as *const _ as usize
- self.drain_pos_.as_ptr() as *const _ as usize)
/ core::mem::size_of::<I::Item>();
(len, Some(len))
}
}
impl<I: Iterator> ExactSizeIterator for Splice<'_, I> {}
impl<I> DoubleEndedIterator for Splice<'_, I>
where
I: Iterator,
{
fn next_back(&mut self) -> Option<Self::Item> {
let pos = unsafe { self.drain_end_.as_ptr().sub(1) };
if pos < self.drain_pos_.as_ptr() {
return None;
}
let tmp = unsafe { core::ptr::read(pos) };
self.drain_end_ = unsafe { core::ptr::NonNull::new_unchecked(pos) };
Some(tmp)
}
}
struct DropGuard<'b, 'a, I>
where
I: Iterator,
{
splice: &'b mut Splice<'a, I>,
}
impl<'b, 'a, I> Drop for DropGuard<'b, 'a, I>
where
I: Iterator,
{
fn drop(&mut self) {
for x in &mut self.splice {
core::mem::drop(x);
}
let vec = unsafe { self.splice.vec_.as_mut() };
if vec.is_default() {
for x in &mut self.splice.fill_ {
vec.push(x);
}
return;
}
let drain_begin = unsafe { vec.as_mut_ptr().add(vec.len()) };
let num_drained = (self.splice.remaining_pos_.as_ptr() as usize - drain_begin as usize)
/ core::mem::size_of::<I::Item>();
let needs_more = {
let mut needs_more = true;
for idx in 0..num_drained {
if let Some(val) = self.splice.fill_.next() {
unsafe {
core::ptr::write(drain_begin.add(idx), val);
vec.set_len(vec.len() + 1);
};
} else {
needs_more = false;
}
}
needs_more
};
if !needs_more {
if unsafe { vec.as_ptr().add(vec.len()) == self.splice.remaining_pos_.as_ptr() } {
unsafe {
vec.set_len(vec.len() + self.splice.remaining_);
}
return;
}
let src = self.splice.remaining_pos_.as_ptr();
let dst = unsafe { vec.as_mut_ptr().add(vec.len()) };
let count = self.splice.remaining_;
unsafe {
core::ptr::copy(src, dst, count);
vec.set_len(vec.len() + self.splice.remaining_);
};
return;
}
let mut tmp: MiniVec<_> = (&mut self.splice.fill_).collect();
let capacity = vec.capacity();
let remaining_offset = (self.splice.remaining_pos_.as_ptr() as usize - vec.as_ptr() as usize)
/ core::mem::size_of::<I::Item>();
let total_elements = vec.len() + self.splice.remaining_ + tmp.len();
if total_elements > capacity {
vec.grow(total_elements, vec.alignment());
}
if self.splice.remaining_ > 0 {
unsafe {
let src = vec.as_ptr().add(remaining_offset);
let dst = vec.as_mut_ptr().add(vec.len() + tmp.len());
let count = self.splice.remaining_;
core::ptr::copy(src, dst, count);
};
}
if !tmp.is_empty() {
unsafe {
let src = tmp.as_ptr();
let dst = vec.as_mut_ptr().add(vec.len());
let count = tmp.len();
core::ptr::copy(src, dst, count);
};
}
unsafe {
vec.set_len(vec.len() + self.splice.remaining_ + tmp.len());
if !tmp.is_empty() {
tmp.set_len(0);
}
};
}
}
impl<I: Iterator> Drop for Splice<'_, I> {
fn drop(&mut self) {
while let Some(item) = self.next() {
let guard = DropGuard { splice: self };
drop(item);
core::mem::forget(guard);
}
DropGuard { splice: self };
}
}