/* Licensed under the Apache License, Version 2.0 or the MIT license * , at your * option. This file may not be copied, modified, or distributed * except according to those terms. * * See the COPYRIGHT file at the top-level directory of this distribution */ //! A thread-safe reference-counted slice type. //! //! Forked from https://github.com/huonw/shared_slice , which doesn't work on //! rust stable. use std::{cmp, fmt, ops}; use std::hash::{Hash, Hasher}; use std::sync::{Arc, Weak}; /// A reference-counted slice type. pub struct ArcSlice { data: *const [T], counts: Arc>, } unsafe impl Send for ArcSlice {} unsafe impl Sync for ArcSlice {} /// A non-owning reference-counted slice type. /// /// This is to `ArcSlice` as `std::sync::Weak` is to `std::sync::Arc`, and /// allows one to have cyclic references without stopping memory from /// being deallocated. pub struct WeakSlice { data: *const [T], counts: Weak>, } unsafe impl Send for WeakSlice {} unsafe impl Sync for WeakSlice {} impl ArcSlice { /// Construct a new `ArcSlice` containing the elements of `slice`. /// /// This reuses the allocation of `slice`. pub fn new(slice: Box<[T]>) -> ArcSlice { ArcSlice { data: &*slice, counts: Arc::new(slice), } } /// Downgrade self into a weak slice. pub fn downgrade(&self) -> WeakSlice { WeakSlice { data: self.data, counts: Arc::downgrade(&self.counts) } } /// Construct a new `ArcSlice` that only points to elements at /// indices `lo` (inclusive) through `hi` (exclusive). /// /// This consumes `self` to avoid unnecessary reference-count /// modifications. Use `.clone()` if it is necessary to refer to /// `self` after calling this. /// /// # Panics /// /// Panics if `lo > hi` or if either are strictly greater than /// `self.len()`. pub fn slice(mut self, lo: usize, hi: usize) -> ArcSlice { self.data = &self[lo..hi]; self } /// Construct a new `ArcSlice` that only points to elements at /// indices up to `hi` (exclusive). /// /// This consumes `self` to avoid unnecessary reference-count /// modifications. Use `.clone()` if it is necessary to refer to /// `self` after calling this. /// /// # Panics /// /// Panics if `hi > self.len()`. pub fn slice_to(self, hi: usize) -> ArcSlice { self.slice(0, hi) } /// Construct a new `ArcSlice` that only points to elements at /// indices starting at `lo` (inclusive). /// /// This consumes `self` to avoid unnecessary reference-count /// modifications. Use `.clone()` if it is necessary to refer to /// `self` after calling this. /// /// # Panics /// /// Panics if `lo > self.len()`. pub fn slice_from(self, lo: usize) -> ArcSlice { let hi = self.len(); self.slice(lo, hi) } } impl Clone for ArcSlice { fn clone(&self) -> ArcSlice { ArcSlice { data: self.data, counts: self.counts.clone() } } } impl ops::Deref for ArcSlice { type Target = [T]; fn deref<'a>(&'a self) -> &'a [T] { unsafe { &*self.data } } } impl AsRef<[T]> for ArcSlice { fn as_ref(&self) -> &[T] { &**self } } impl PartialEq for ArcSlice { fn eq(&self, other: &ArcSlice) -> bool { **self == **other } fn ne(&self, other: &ArcSlice) -> bool { **self != **other } } impl Eq for ArcSlice {} impl PartialOrd for ArcSlice { fn partial_cmp(&self, other: &ArcSlice) -> Option { (**self).partial_cmp(&**other) } fn lt(&self, other: &ArcSlice) -> bool { **self < **other } fn le(&self, other: &ArcSlice) -> bool { **self <= **other } fn gt(&self, other: &ArcSlice) -> bool { **self > **other } fn ge(&self, other: &ArcSlice) -> bool { **self >= **other } } impl Ord for ArcSlice { fn cmp(&self, other: &ArcSlice) -> cmp::Ordering { (**self).cmp(&**other) } } impl Hash for ArcSlice { fn hash(&self, state: &mut H) { Hash::hash(&**self, state) } } impl fmt::Debug for ArcSlice { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } impl WeakSlice { /// Attempt to upgrade `self` to a strongly-counted `ArcSlice`. /// /// Returns `None` if this is not possible (the data has already /// been freed). pub fn upgrade(&self) -> Option> { self.counts.upgrade().map(|counts| { ArcSlice { data: self.data, counts: counts } }) } } #[cfg(test)] mod tests { use std::cell::Cell; use std::cmp::Ordering; use std::sync::{Arc, Mutex}; use super::{ArcSlice, WeakSlice}; #[test] fn clone() { let x = ArcSlice::new(Box::new([Cell::new(false)])); let y = x.clone(); assert_eq!(x[0].get(), false); assert_eq!(y[0].get(), false); x[0].set(true); assert_eq!(x[0].get(), true); assert_eq!(y[0].get(), true); } #[test] fn test_upgrade_downgrade() { let x = ArcSlice::new(Box::new([1])); let y: WeakSlice<_> = x.downgrade(); assert_eq!(y.upgrade(), Some(x.clone())); drop(x); assert!(y.upgrade().is_none()) } #[test] fn test_total_cmp() { let x = ArcSlice::new(Box::new([1, 2, 3])); let y = ArcSlice::new(Box::new([1, 2, 3])); let z = ArcSlice::new(Box::new([1, 2, 4])); assert_eq!(x, x); assert_eq!(x, y); assert!(x != z); assert!(y != z); assert!(x < z); assert!(x <= z); assert!(!(x > z)); assert!(!(x >= z)); assert!(!(z < x)); assert!(!(z <= x)); assert!(z > x); assert!(z >= x); assert_eq!(x.partial_cmp(&x), Some(Ordering::Equal)); assert_eq!(x.partial_cmp(&y), Some(Ordering::Equal)); assert_eq!(x.partial_cmp(&z), Some(Ordering::Less)); assert_eq!(z.partial_cmp(&y), Some(Ordering::Greater)); assert_eq!(x.cmp(&x), Ordering::Equal); assert_eq!(x.cmp(&y), Ordering::Equal); assert_eq!(x.cmp(&z), Ordering::Less); assert_eq!(z.cmp(&y), Ordering::Greater); } #[test] fn test_partial_cmp() { use std::f64; let x = ArcSlice::new(Box::new([1.0, f64::NAN])); let y = ArcSlice::new(Box::new([1.0, f64::NAN])); let z = ArcSlice::new(Box::new([2.0, f64::NAN])); let w = ArcSlice::new(Box::new([f64::NAN, 1.0])); assert!(!(x == y)); assert!(x != y); assert!(!(x < y)); assert!(!(x <= y)); assert!(!(x > y)); assert!(!(x >= y)); assert!(x < z); assert!(x <= z); assert!(!(x > z)); assert!(!(x >= z)); assert!(!(z < w)); assert!(!(z <= w)); assert!(!(z > w)); assert!(!(z >= w)); assert_eq!(x.partial_cmp(&x), None); assert_eq!(x.partial_cmp(&y), None); assert_eq!(x.partial_cmp(&z), Some(Ordering::Less)); assert_eq!(z.partial_cmp(&x), Some(Ordering::Greater)); assert_eq!(x.partial_cmp(&w), None); assert_eq!(y.partial_cmp(&w), None); assert_eq!(z.partial_cmp(&w), None); assert_eq!(w.partial_cmp(&w), None); } #[test] fn test_show() { let x = ArcSlice::new(Box::new([1, 2])); assert_eq!(format!("{:?}", x), "[1, 2]"); let y: ArcSlice = ArcSlice::new(Box::new([])); assert_eq!(format!("{:?}", y), "[]"); } #[test] fn test_slice() { let x = ArcSlice::new(Box::new([1, 2, 3])); let real = [1, 2, 3]; for i in 0..3 + 1 { for j in i..3 + 1 { let slice: ArcSlice<_> = x.clone().slice(i, j); assert_eq!(&*slice, &real[i..j]); } assert_eq!(&*x.clone().slice_to(i), &real[..i]); assert_eq!(&*x.clone().slice_from(i), &real[i..]); } } #[test] fn test_send_sync() { fn assert_send() {} fn assert_sync() {} assert_send::>(); assert_sync::>(); assert_send::>(); assert_sync::>(); } #[test] fn test_drop() { let drop_flag = Arc::new(Mutex::new(0)); struct Foo(Arc>); impl Drop for Foo { fn drop(&mut self) { let mut n = self.0.lock().unwrap(); *n += 1; } } let whole = ArcSlice::new(Box::new([Foo(drop_flag.clone()), Foo(drop_flag.clone())])); drop(whole); assert_eq!(*drop_flag.lock().unwrap(), 2); *drop_flag.lock().unwrap() = 0; let whole = ArcSlice::new(Box::new([Foo(drop_flag.clone()), Foo(drop_flag.clone())])); let part = whole.slice(1, 2); drop(part); assert_eq!(*drop_flag.lock().unwrap(), 2); } }