use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use std::{
fmt,
mem::{self, ManuallyDrop},
};
use triomphe::Arc;
use crate::inner;
pub struct SlotHeap<T> {
inner: Arc<RwLock<inner::SlotHeap<T>>>,
}
impl<T> SlotHeap<T>
where
T: PartialOrd,
{
pub fn new() -> Self {
Self {
inner: Arc::new(inner::SlotHeap::new().into()),
}
}
pub fn len(&self) -> usize {
self.inner.read().len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn insert(&self, value: T) -> (SlotHeapId<T>, bool) {
let from = ManuallyDrop::new(self.inner.clone());
let mut guard = self.inner.write();
let (id, is_top) = guard.insert(value);
(SlotHeapId { from, id }, is_top)
}
pub fn peek(&self) -> Option<SlotHeapPeek<'_, T>> {
let guard = self.inner.read();
(!guard.is_empty()).then(|| SlotHeapPeek { guard })
}
pub fn peek_mut(&self) -> Option<SlotHeapPeekMut<'_, T>> {
let guard = self.inner.write();
(!guard.is_empty()).then(|| SlotHeapPeekMut {
guard,
dirty: false,
})
}
}
impl<T> Default for SlotHeap<T>
where
T: PartialOrd,
{
fn default() -> Self {
Self::new()
}
}
pub struct SlotHeapId<T>
where
T: PartialOrd,
{
from: ManuallyDrop<Arc<RwLock<inner::SlotHeap<T>>>>,
id: usize,
}
impl<T> SlotHeapId<T>
where
T: PartialOrd,
{
pub fn into_inner(mut self) -> (T, bool) {
let mut guard = self.from.write();
let item = unsafe { guard.remove_unchecked(self.id) };
drop(guard);
unsafe { ManuallyDrop::drop(&mut self.from) };
mem::forget(self);
item
}
pub fn get(&self) -> SlotHeapRef<'_, T> {
SlotHeapRef {
guard: self.from.read(),
id: self.id,
}
}
pub fn get_mut(&self) -> SlotHeapRefMut<'_, T> {
SlotHeapRefMut {
guard: self.from.write(),
id: self.id,
dirty: false,
}
}
}
impl<T> fmt::Debug for SlotHeapId<T>
where
T: PartialOrd,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SlotHeapId")
.field("from", &self.from.as_ptr())
.field("id", &self.id)
.finish()
}
}
impl<T> Drop for SlotHeapId<T>
where
T: PartialOrd,
{
fn drop(&mut self) {
let mut guard = self.from.write();
unsafe { guard.remove_unchecked(self.id) };
drop(guard);
unsafe { ManuallyDrop::drop(&mut self.from) }
}
}
pub struct SlotHeapPeek<'a, T>
where
T: PartialOrd,
{
guard: RwLockReadGuard<'a, inner::SlotHeap<T>>,
}
#[reflica::reflica]
impl<T> SlotHeapPeek<'_, T>
where
T: PartialOrd,
{
fn deref(&self) -> &T {
unsafe { self.guard.peek_unchecked() }
}
}
pub struct SlotHeapPeekMut<'a, T>
where
T: PartialOrd,
{
guard: RwLockWriteGuard<'a, inner::SlotHeap<T>>,
dirty: bool,
}
#[reflica::reflica]
impl<T> SlotHeapPeekMut<'_, T>
where
T: PartialOrd,
{
pub fn finish(mut self) -> bool {
let is_top = if self.dirty {
unsafe { self.guard.heapify_down(0) == 0 }
} else {
true
};
mem::forget(self);
is_top
}
fn deref(&self) -> &T {
unsafe { self.guard.peek_unchecked() }
}
fn deref_mut(&mut self) -> &mut T {
self.dirty = true;
unsafe { self.guard.peek_unchecked_mut() }
}
}
impl<T> Drop for SlotHeapPeekMut<'_, T>
where
T: PartialOrd,
{
fn drop(&mut self) {
if self.dirty {
unsafe { self.guard.heapify_down(0) };
}
}
}
pub struct SlotHeapRef<'a, T>
where
T: PartialOrd,
{
guard: RwLockReadGuard<'a, inner::SlotHeap<T>>,
id: usize,
}
#[reflica::reflica]
impl<T> SlotHeapRef<'_, T>
where
T: PartialOrd,
{
pub fn is_top(&self) -> bool {
unsafe { self.guard.get_unchecked_index(self.id) == 0 }
}
fn deref(&self) -> &T {
unsafe { self.guard.get_unchecked(self.id) }
}
}
pub struct SlotHeapRefMut<'a, T>
where
T: PartialOrd,
{
guard: RwLockWriteGuard<'a, inner::SlotHeap<T>>,
id: usize,
dirty: bool,
}
#[reflica::reflica]
impl<T> SlotHeapRefMut<'_, T>
where
T: PartialOrd,
{
pub fn is_top(&self) -> bool {
unsafe { self.guard.get_unchecked_index(self.id) == 0 }
}
pub fn finish(mut self) -> bool {
let is_top = if self.dirty {
let index = unsafe { self.guard.get_unchecked_index(self.id) };
unsafe { self.guard.heapify(index) == 0 }
} else {
true
};
mem::forget(self);
is_top
}
fn deref(&self) -> &T {
unsafe { self.guard.get_unchecked(self.id) }
}
fn deref_mut(&mut self) -> &mut T {
self.dirty = true;
unsafe { self.guard.get_unchecked_mut(self.id) }
}
}
impl<T> Drop for SlotHeapRefMut<'_, T>
where
T: PartialOrd,
{
fn drop(&mut self) {
if self.dirty {
let index = unsafe { self.guard.get_unchecked_index(self.id) };
unsafe {
self.guard.heapify(index);
}
}
}
}
unsafe impl<T> Send for SlotHeap<T> where T: Send + PartialOrd {}
unsafe impl<T> Sync for SlotHeap<T> where T: Send + Sync + PartialOrd {}
unsafe impl<T> Send for SlotHeapId<T> where T: Send + PartialOrd {}
unsafe impl<T> Sync for SlotHeapId<T> where T: Send + Sync + PartialOrd {}
unsafe impl<T> Send for SlotHeapPeek<'_, T> where T: Send + Sync + PartialOrd {}
unsafe impl<T> Sync for SlotHeapPeek<'_, T> where T: Send + Sync + PartialOrd {}
unsafe impl<T> Send for SlotHeapPeekMut<'_, T> where T: Send + PartialOrd {}
unsafe impl<T> Sync for SlotHeapPeekMut<'_, T> where T: Send + Sync + PartialOrd {}
unsafe impl<T> Send for SlotHeapRef<'_, T> where T: Send + Sync + PartialOrd {}
unsafe impl<T> Sync for SlotHeapRef<'_, T> where T: Send + Sync + PartialOrd {}
unsafe impl<T> Send for SlotHeapRefMut<'_, T> where T: Send + PartialOrd {}
unsafe impl<T> Sync for SlotHeapRefMut<'_, T> where T: Send + Sync + PartialOrd {}