use super::Caches;
use elysees::Arc;
use erasable::Thin;
use slice_dst::SliceWithHeader;
use itertools::Itertools;
use std::fmt::{self, Debug, Formatter};
use std::hash::{Hash, Hasher};
use std::iter::FromIterator;
use std::ops::Deref;
type ThinArc<H, T> = Thin<Arc<SliceWithHeader<H, T>>>;
#[repr(transparent)]
pub struct CachedArr<A, P = (), H = ()> {
ptr: Option<ThinArc<H, A>>,
predicate: std::marker::PhantomData<P>,
}
impl<A, P: EmptyPredicate> Default for CachedArr<A, P> {
fn default() -> CachedArr<A, P> {
CachedArr::EMPTY
}
}
impl<A: Eq + Deref, P> Caches<[A]> for CachedArr<A, P> {
#[inline]
fn can_collect(&self) -> bool {
if let Some(ptr) = &self.ptr {
Thin::with(ptr, |p| p.is_unique())
} else {
true
}
}
}
impl<A, P, H> Clone for CachedArr<A, P, H> {
#[inline]
fn clone(&self) -> CachedArr<A, P, H> {
CachedArr {
ptr: self.ptr.clone(),
predicate: self.predicate,
}
}
}
impl<A: Deref, P, Q, H> PartialEq<CachedArr<A, P, H>> for CachedArr<A, Q, H> {
#[inline]
fn eq(&self, other: &CachedArr<A, P, H>) -> bool {
let lhs = self.as_slice();
let rhs = other.as_slice();
if lhs.len() != rhs.len() {
return false;
}
for (l, r) in lhs.iter().zip(rhs.iter()) {
if l.deref() as *const A::Target != r.deref() as *const A::Target {
return false;
}
}
return true;
}
}
impl<A: Deref, P, H> Eq for CachedArr<A, P, H> {}
impl<A, P, H> CachedArr<A, P, H> {
#[inline]
pub fn as_ptr(&self) -> *const A {
self.as_slice()
.first()
.map(|f| f as *const A)
.unwrap_or(std::ptr::null())
}
#[inline]
pub fn as_slice(&self) -> &[A] {
self.ptr.as_ref().map(|p| &p.slice).unwrap_or(&[])
}
#[inline]
pub fn iter(&self) -> std::slice::Iter<A> {
self.as_slice().iter()
}
#[inline]
pub fn as_arr(&self) -> &CachedArr<A, (), H> {
self.coerce_ref()
}
#[inline]
pub fn into_arr(self) -> CachedArr<A, (), H> {
self.coerce()
}
#[inline]
pub fn coerce<Q>(self) -> CachedArr<A, Q, H> {
CachedArr {
ptr: self.ptr,
predicate: std::marker::PhantomData,
}
}
#[inline]
pub fn coerce_ref<Q>(&self) -> &CachedArr<A, Q, H> {
unsafe { std::mem::transmute(self) }
}
}
impl<A, P> Debug for CachedArr<A, P>
where
A: Debug,
{
#[inline]
fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
Debug::fmt(self.as_slice(), fmt)
}
}
impl<A, P> Hash for CachedArr<A, P>
where
A: Deref,
{
#[inline]
fn hash<H: Hasher>(&self, hasher: &mut H) {
for value in self.as_slice().iter() {
std::ptr::hash(value.deref() as *const _, hasher)
}
}
}
impl<A, P> Deref for CachedArr<A, P> {
type Target = [A];
#[inline]
fn deref(&self) -> &[A] {
self.as_slice()
}
}
impl<A> CachedArr<A> {
pub fn from_exact<I: ExactSizeIterator + Iterator<Item = A>>(iter: I) -> CachedArr<A> {
if iter.len() == 0 {
CachedArr::EMPTY
} else {
let ptr: Arc<_> = SliceWithHeader::new((), iter);
CachedArr {
ptr: Some(ptr.into()),
predicate: std::marker::PhantomData,
}
}
}
}
impl<A> From<Vec<A>> for CachedArr<A> {
fn from(v: Vec<A>) -> CachedArr<A> {
Self::from_exact(v.into_iter())
}
}
impl<A: Clone> From<&'_ [A]> for CachedArr<A> {
fn from(v: &[A]) -> CachedArr<A> {
Self::from_exact(v.iter().cloned())
}
}
impl<A: Deref> From<Vec<A>> for CachedBag<A> {
fn from(mut v: Vec<A>) -> CachedBag<A> {
v.sort_unstable_by_key(|a| a.deref() as *const _);
CachedArr::<A>::from(v).coerce()
}
}
impl<A: Deref> From<Vec<A>> for CachedSet<A> {
fn from(mut v: Vec<A>) -> CachedSet<A> {
v.sort_unstable_by_key(|a| (*a).deref() as *const _);
v.dedup_by_key(|a| (*a).deref() as *const _);
CachedArr::<A>::from(v).coerce()
}
}
impl<A> FromIterator<A> for CachedArr<A> {
fn from_iter<I: IntoIterator<Item = A>>(iter: I) -> CachedArr<A> {
iter.into_iter().collect_vec().into()
}
}
impl<A: Deref> FromIterator<A> for CachedBag<A> {
fn from_iter<I: IntoIterator<Item = A>>(iter: I) -> CachedBag<A> {
iter.into_iter().collect_vec().into()
}
}
impl<A: Deref> FromIterator<A> for CachedSet<A> {
fn from_iter<I: IntoIterator<Item = A>>(iter: I) -> CachedSet<A> {
iter.into_iter().collect_vec().into()
}
}
pub trait EmptyPredicate {}
impl EmptyPredicate for () {}
impl<A, P: EmptyPredicate> CachedArr<A, P> {
pub const EMPTY: CachedArr<A, P> = CachedArr {
ptr: None,
predicate: std::marker::PhantomData,
};
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct Sorted;
pub trait BagMarker {}
impl BagMarker for Sorted {}
impl EmptyPredicate for Sorted {}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct Uniq;
pub trait SetMarker: BagMarker {}
impl BagMarker for Uniq {}
impl SetMarker for Uniq {}
impl EmptyPredicate for Uniq {}
impl<A: Deref, P, H> CachedArr<A, P, H> {
pub fn is_sorted(&self) -> bool {
self.as_slice()
.windows(2)
.all(|w| w[0].deref() as *const _ <= w[1].deref() as *const _)
}
pub fn is_set(&self) -> bool {
self.as_slice()
.windows(2)
.all(|w| w[0].deref() as *const _ < w[1].deref() as *const _)
}
pub fn try_as_bag(&self) -> Result<&CachedBag<A, H>, &Self> {
if self.is_sorted() {
Ok(self.coerce_ref())
} else {
Err(self)
}
}
pub fn try_as_set(&self) -> Result<&CachedSet<A, H>, &Self> {
if self.is_set() {
Ok(self.coerce_ref())
} else {
Err(self)
}
}
pub fn sorted(&self) -> CachedBag<A>
where
A: Clone,
{
CachedBag::from(self.iter().cloned().collect_vec())
}
pub fn set(&self) -> CachedSet<A>
where
A: Clone,
{
CachedSet::from(self.iter().cloned().collect_vec())
}
pub fn try_into_bag(self) -> Result<CachedBag<A, H>, Self> {
if self.is_sorted() {
Ok(self.coerce())
} else {
Err(self)
}
}
pub fn try_into_set(self) -> Result<CachedSet<A, H>, Self> {
if self.is_set() {
Ok(self.coerce())
} else {
Err(self)
}
}
}
impl<A: Deref, P: BagMarker, H> CachedArr<A, P, H> {
pub fn as_bag(&self) -> &CachedBag<A, H> {
self.coerce_ref()
}
pub fn into_bag(self) -> CachedBag<A, H> {
self.coerce()
}
}
impl<A: Deref, P: SetMarker, H> CachedArr<A, P, H> {
pub fn as_set(&self) -> &CachedSet<A, H> {
self.coerce_ref()
}
pub fn into_set(self) -> CachedSet<A, H> {
self.coerce()
}
}
pub type CachedBag<A, H = ()> = CachedArr<A, Sorted, H>;
impl<A: Deref + Clone, H> CachedBag<A, H> {
pub fn contains_impl(&self, item: *const A::Target) -> Option<&A> {
self.as_slice()
.binary_search_by_key(&item, |a| (*a).deref() as *const A::Target)
.ok()
.map(|ix| &self.as_slice()[ix])
}
pub fn uniq_impl(&self) -> CachedSet<A> {
let mut v = self.iter().cloned().collect_vec();
v.dedup_by_key(|a| (*a).deref() as *const A::Target);
CachedArr::<A>::from(v).coerce()
}
}
impl<A: Deref + Clone> CachedBag<A> {
pub fn merge_impl(&self, rhs: &CachedBag<A>) -> CachedBag<A> {
if rhs.is_empty() {
return self.clone();
} else if self.is_empty() {
return rhs.clone();
}
let union = self
.iter()
.merge_by(rhs.iter(), |l, r| {
(*l).deref() as *const A::Target <= (*r).deref() as *const A::Target
})
.cloned()
.collect_vec();
CachedArr::<A>::from(union).coerce()
}
pub fn intersect_impl(&self, rhs: &CachedBag<A>) -> CachedBag<A> {
if rhs.is_empty() {
return rhs.clone();
} else if self.is_empty() {
return self.clone();
}
let intersection = self
.iter()
.merge_join_by(rhs.iter(), |l, r| {
((*l).deref() as *const A::Target).cmp(&((*r).deref() as *const A::Target))
})
.filter_map(|v| v.both().map(|(l, _)| l))
.cloned()
.collect_vec();
CachedArr::<A>::from(intersection).coerce()
}
}
impl<A: Deref + Clone, P: BagMarker, H> CachedArr<A, P, H> {
pub fn contains(&self, item: *const A::Target) -> Option<&A> {
self.coerce_ref().contains_impl(item)
}
}
impl<A: Deref + Clone, P: BagMarker> CachedArr<A, P> {
#[inline]
pub fn merge<Q: BagMarker>(&self, rhs: &CachedArr<A, Q>) -> CachedBag<A> {
self.coerce_ref().merge_impl(rhs.coerce_ref())
}
#[inline]
pub fn intersect<Q: BagMarker>(&self, rhs: &CachedArr<A, Q>) -> CachedArr<A, P> {
self.coerce_ref().intersect_impl(rhs.coerce_ref()).coerce()
}
#[inline]
pub fn uniq(&self) -> CachedSet<A> {
self.coerce_ref().uniq_impl()
}
}
pub type CachedSet<A, H = ()> = CachedArr<A, Uniq, H>;
impl<A: Deref + Clone> CachedSet<A> {
pub fn union_impl(&self, rhs: &CachedSet<A>) -> CachedSet<A> {
if rhs.is_empty() {
return self.clone();
} else if self.is_empty() {
return rhs.clone();
}
let union = self
.iter()
.merge_join_by(rhs.iter(), |l, r| {
((*l).deref() as *const A::Target).cmp(&((*r).deref() as *const A::Target))
})
.map(|v| v.reduce(|l, _| l))
.cloned()
.collect_vec();
CachedArr::<A>::from(union).coerce()
}
}
impl<A: Deref + Clone, P: SetMarker> CachedArr<A, P> {
pub fn union<Q: SetMarker>(&self, rhs: &CachedArr<A, Q>) -> CachedSet<A> {
self.coerce_ref().union_impl(rhs.coerce_ref())
}
}