use crate::utils::assume;
use std::{mem::forget, ptr};
pub(super) fn dedup_payload_starting_at<'a, T, P, F>(
keys: &'a mut Vec<T>,
payload: P,
starting_point: usize,
mut same_bucket: F,
) where
P: Payload<'a>,
F: FnMut(&mut T, P::ItemRefMut, &mut T, P::ItemRefMut) -> bool,
{
assert!(payload.len().equal_to(keys.len()));
let len = keys.len();
if len <= 1 || starting_point + 1 >= keys.len() {
return;
}
struct FillGapOnDrop<'a, T, P>
where
P: Payload<'a>,
{
read: usize,
write: usize,
keys: &'a mut Vec<T>,
payload: P,
}
impl<'a, T, P> Drop for FillGapOnDrop<'a, T, P>
where
P: Payload<'a>,
{
fn drop(&mut self) {
unsafe {
let len = self.keys.len();
assume(self.payload.len().equal_to(self.keys.len()));
let key_ptr = self.keys.as_mut_ptr();
let payload_ptr = self.payload.as_mut_ptr();
let items_left = len.wrapping_sub(self.read);
let dropped_key_ptr = key_ptr.add(self.write);
let dropped_payload_ptr = payload_ptr.add(self.write);
let valid_key_ptr = key_ptr.add(self.read);
let valid_payload_ptr = payload_ptr.add(self.read);
ptr::copy(valid_key_ptr, dropped_key_ptr, items_left);
P::copy_payload(valid_payload_ptr, dropped_payload_ptr, items_left);
let dropped = self.read.wrapping_sub(self.write);
self.keys.set_len(len - dropped);
self.payload.set_len(len - dropped);
}
}
}
let mut gap = FillGapOnDrop {
read: starting_point + 1,
write: starting_point + 1,
keys,
payload,
};
let key_ptr = gap.keys.as_mut_ptr();
let payload_ptr = gap.payload.as_mut_ptr();
unsafe {
while gap.read < len {
let read_key_ptr = key_ptr.add(gap.read);
let read_payload_ptr = payload_ptr.add(gap.read);
let prev_key_ptr = key_ptr.add(gap.write.wrapping_sub(1));
let prev_payload_ptr = payload_ptr.add(gap.write.wrapping_sub(1));
if same_bucket(
&mut *read_key_ptr,
P::deref_mut(read_payload_ptr),
&mut *prev_key_ptr,
P::deref_mut(prev_payload_ptr),
) {
gap.read += 1;
ptr::drop_in_place(read_key_ptr);
P::drop_payload_in_place(read_payload_ptr);
} else {
let write_key_ptr = key_ptr.add(gap.write);
let write_payload_ptr = payload_ptr.add(gap.write);
ptr::copy(read_key_ptr, write_key_ptr, 1);
P::copy_payload(read_payload_ptr, write_payload_ptr, 1);
gap.write += 1;
gap.read += 1;
}
}
gap.keys.set_len(gap.write);
gap.payload.set_len(gap.write);
forget(gap);
}
}
#[cfg(test)]
pub(super) fn retain_starting_at<T, F>(vec: &mut Vec<T>, starting_point: usize, mut retain: F)
where
F: FnMut(&mut T) -> bool,
{
if vec.is_empty() || starting_point >= vec.len() {
return;
}
let original_len = vec.len();
unsafe { vec.set_len(0) };
struct BackshiftOnDrop<'a, T> {
v: &'a mut Vec<T>,
processed_len: usize,
deleted_cnt: usize,
original_len: usize,
}
impl<T> Drop for BackshiftOnDrop<'_, T> {
fn drop(&mut self) {
if self.deleted_cnt > 0 {
unsafe {
ptr::copy(
self.v.as_ptr().add(self.processed_len),
self.v
.as_mut_ptr()
.add(self.processed_len - self.deleted_cnt),
self.original_len - self.processed_len,
);
}
}
unsafe {
self.v.set_len(self.original_len - self.deleted_cnt);
}
}
}
let mut g = BackshiftOnDrop {
v: vec,
processed_len: starting_point,
deleted_cnt: 0,
original_len,
};
fn process_loop<F, T, const DELETED: bool>(
original_len: usize,
f: &mut F,
g: &mut BackshiftOnDrop<'_, T>,
) where
F: FnMut(&mut T) -> bool,
{
while g.processed_len != original_len {
let cur = unsafe { &mut *g.v.as_mut_ptr().add(g.processed_len) };
if !f(cur) {
g.processed_len += 1;
g.deleted_cnt += 1;
unsafe { ptr::drop_in_place(cur) };
if DELETED {
continue;
} else {
break;
}
}
if DELETED {
unsafe {
let hole_slot = g.v.as_mut_ptr().add(g.processed_len - g.deleted_cnt);
ptr::copy_nonoverlapping(cur, hole_slot, 1);
}
}
g.processed_len += 1;
}
}
process_loop::<F, T, false>(original_len, &mut retain, &mut g);
process_loop::<F, T, true>(original_len, &mut retain, &mut g);
drop(g);
}
pub(super) fn retain_payload_starting_at<K, P, F>(
keys: &mut Vec<K>,
payload: &mut Vec<P>,
starting_point: usize,
mut retain: F,
) where
F: FnMut(&mut K, &mut P) -> bool,
{
assert_eq!(keys.len(), payload.len());
if keys.is_empty() || starting_point >= keys.len() {
return;
}
let original_len = keys.len();
unsafe {
keys.set_len(0);
payload.set_len(0);
}
struct BackshiftOnDrop<'a, K, P> {
keys: &'a mut Vec<K>,
payload: &'a mut Vec<P>,
processed_len: usize,
deleted_cnt: usize,
original_len: usize,
}
impl<K, P> Drop for BackshiftOnDrop<'_, K, P> {
fn drop(&mut self) {
if self.deleted_cnt > 0 {
unsafe {
let src = self.processed_len;
let dest = self.processed_len - self.deleted_cnt;
let count = self.original_len - self.processed_len;
ptr::copy(
self.keys.as_ptr().add(src),
self.keys.as_mut_ptr().add(dest),
count,
);
ptr::copy(
self.payload.as_ptr().add(src),
self.payload.as_mut_ptr().add(dest),
count,
);
}
}
unsafe {
let length = self.original_len - self.deleted_cnt;
self.keys.set_len(length);
self.payload.set_len(length);
}
}
}
let mut guard = BackshiftOnDrop {
keys,
payload,
processed_len: starting_point,
deleted_cnt: 0,
original_len,
};
fn process_loop<K, P, F, const DELETED: bool>(
original_len: usize,
retain: &mut F,
guard: &mut BackshiftOnDrop<'_, K, P>,
) where
F: FnMut(&mut K, &mut P) -> bool,
{
while guard.processed_len != original_len {
let (current_key, current_payload) = unsafe {
(
&mut *guard.keys.as_mut_ptr().add(guard.processed_len),
&mut *guard.payload.as_mut_ptr().add(guard.processed_len),
)
};
if !retain(current_key, current_payload) {
guard.processed_len += 1;
guard.deleted_cnt += 1;
unsafe {
ptr::drop_in_place(current_key);
ptr::drop_in_place(current_payload);
}
if DELETED {
continue;
} else {
break;
}
}
if DELETED {
unsafe {
let slot_start = guard.processed_len - guard.deleted_cnt;
let key_hole_slot = guard.keys.as_mut_ptr().add(slot_start);
ptr::copy_nonoverlapping(current_key, key_hole_slot, 1);
let payload_hole_slot = guard.payload.as_mut_ptr().add(slot_start);
ptr::copy_nonoverlapping(current_payload, payload_hole_slot, 1);
}
}
guard.processed_len += 1;
}
}
process_loop::<K, P, F, false>(original_len, &mut retain, &mut guard);
process_loop::<K, P, F, true>(original_len, &mut retain, &mut guard);
drop(guard);
}
pub(super) trait Payload<'a> {
type Len: PayloadLen;
type Ptr: PayloadPtr;
type ItemRefMut;
fn len(&self) -> Self::Len;
fn as_ptr(&self) -> Self::Ptr;
fn as_mut_ptr(&mut self) -> Self::Ptr;
unsafe fn set_len(&mut self, len: usize);
unsafe fn copy_payload(src: Self::Ptr, dest: Self::Ptr, count: usize);
#[allow(dead_code)]
unsafe fn copy_payload_nonoverlapping(src: Self::Ptr, dest: Self::Ptr, count: usize);
unsafe fn drop_payload_in_place(payload: Self::Ptr);
unsafe fn deref_mut(payload: Self::Ptr) -> Self::ItemRefMut;
}
impl Payload<'_> for () {
type Len = ();
type Ptr = ();
type ItemRefMut = ();
fn len(&self) -> Self::Len {}
fn as_ptr(&self) -> Self::Ptr {}
fn as_mut_ptr(&mut self) -> Self::Ptr {}
unsafe fn set_len(&mut self, _len: usize) {}
unsafe fn copy_payload(_src: Self::Ptr, _dest: Self::Ptr, _count: usize) {}
unsafe fn copy_payload_nonoverlapping(_src: Self::Ptr, _dest: Self::Ptr, _count: usize) {}
unsafe fn drop_payload_in_place(_payload: Self::Ptr) {}
unsafe fn deref_mut(_payload: Self::Ptr) -> Self::ItemRefMut {}
}
impl<'a, T> Payload<'a> for &'a mut Vec<T> {
type Len = usize;
type Ptr = *mut T;
type ItemRefMut = &'a mut T;
fn len(&self) -> Self::Len {
Vec::len(self)
}
fn as_ptr(&self) -> Self::Ptr {
Vec::as_ptr(self) as *mut T
}
fn as_mut_ptr(&mut self) -> Self::Ptr {
Vec::as_mut_ptr(self)
}
unsafe fn set_len(&mut self, len: usize) {
unsafe {
Vec::set_len(self, len);
}
}
unsafe fn copy_payload(src: Self::Ptr, dest: Self::Ptr, count: usize) {
unsafe {
ptr::copy(src, dest, count);
}
}
unsafe fn copy_payload_nonoverlapping(src: Self::Ptr, dest: Self::Ptr, count: usize) {
unsafe {
ptr::copy_nonoverlapping(src, dest, count);
}
}
unsafe fn drop_payload_in_place(payload: Self::Ptr) {
unsafe {
ptr::drop_in_place(payload);
}
}
unsafe fn deref_mut(payload: Self::Ptr) -> Self::ItemRefMut {
unsafe { &mut *payload }
}
}
impl<'a, P1, P2> Payload<'a> for (P1, P2)
where
P1: Payload<'a>,
P2: Payload<'a>,
{
type Len = (P1::Len, P2::Len);
type Ptr = (P1::Ptr, P2::Ptr);
type ItemRefMut = (P1::ItemRefMut, P2::ItemRefMut);
fn len(&self) -> Self::Len {
(self.0.len(), self.1.len())
}
fn as_ptr(&self) -> Self::Ptr {
(self.0.as_ptr(), self.1.as_ptr())
}
fn as_mut_ptr(&mut self) -> Self::Ptr {
(self.0.as_mut_ptr(), self.1.as_mut_ptr())
}
unsafe fn set_len(&mut self, len: usize) {
unsafe {
self.0.set_len(len);
self.1.set_len(len);
}
}
unsafe fn copy_payload(src: Self::Ptr, dest: Self::Ptr, count: usize) {
unsafe {
P1::copy_payload(src.0, dest.0, count);
P2::copy_payload(src.1, dest.1, count);
}
}
unsafe fn copy_payload_nonoverlapping(src: Self::Ptr, dest: Self::Ptr, count: usize) {
unsafe {
P1::copy_payload_nonoverlapping(src.0, dest.0, count);
P2::copy_payload_nonoverlapping(src.1, dest.1, count);
}
}
unsafe fn drop_payload_in_place(payload: Self::Ptr) {
unsafe {
P1::drop_payload_in_place(payload.0);
P2::drop_payload_in_place(payload.1);
}
}
unsafe fn deref_mut(payload: Self::Ptr) -> Self::ItemRefMut {
unsafe { (P1::deref_mut(payload.0), P2::deref_mut(payload.1)) }
}
}
pub(super) trait PayloadLen: Copy + 'static {
fn equal_to(&self, len: usize) -> bool;
#[allow(dead_code)]
fn is_empty(&self) -> bool {
self.equal_to(0)
}
#[allow(dead_code)]
fn from_usize(len: usize) -> Self;
}
impl PayloadLen for () {
fn equal_to(&self, _len: usize) -> bool {
true
}
fn from_usize(_len: usize) -> Self {}
}
impl PayloadLen for usize {
fn equal_to(&self, len: usize) -> bool {
len == *self
}
fn from_usize(len: usize) -> Self {
len
}
}
impl<L1, L2> PayloadLen for (L1, L2)
where
L1: PayloadLen,
L2: PayloadLen,
{
fn equal_to(&self, len: usize) -> bool {
self.0.equal_to(len) && self.1.equal_to(len)
}
fn from_usize(len: usize) -> Self {
(L1::from_usize(len), L2::from_usize(len))
}
}
pub(super) trait PayloadPtr: Copy {
#[allow(dead_code)]
unsafe fn offset(self, count: isize) -> Self;
unsafe fn add(self, count: usize) -> Self;
#[allow(dead_code)]
unsafe fn sub(self, count: usize) -> Self;
}
impl PayloadPtr for () {
unsafe fn offset(self, _count: isize) -> Self {}
unsafe fn add(self, _count: usize) -> Self {}
unsafe fn sub(self, _count: usize) -> Self {}
}
impl<T> PayloadPtr for *mut T {
unsafe fn offset(self, count: isize) -> Self {
unsafe { self.offset(count) }
}
unsafe fn add(self, count: usize) -> Self {
unsafe { self.add(count) }
}
unsafe fn sub(self, count: usize) -> Self {
unsafe { self.sub(count) }
}
}
impl<P1, P2> PayloadPtr for (P1, P2)
where
P1: PayloadPtr,
P2: PayloadPtr,
{
unsafe fn offset(self, count: isize) -> Self {
unsafe { (self.0.offset(count), self.1.offset(count)) }
}
unsafe fn add(self, count: usize) -> Self {
unsafe { (self.0.add(count), self.1.add(count)) }
}
unsafe fn sub(self, count: usize) -> Self {
unsafe { (self.0.sub(count), self.1.sub(count)) }
}
}