Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into eq
Browse files Browse the repository at this point in the history
  • Loading branch information
aminya committed Oct 23, 2023
2 parents b2cae94 + 3750bca commit a9ac01b
Show file tree
Hide file tree
Showing 3 changed files with 224 additions and 0 deletions.
53 changes: 53 additions & 0 deletions src/index_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,24 @@ impl<K: Eq + Hash, V> FrozenIndexMap<K, V> {
impl<K: Eq + Hash, V: StableDeref, S: BuildHasher> FrozenIndexMap<K, V, S> {
// these should never return &K or &V
// these should never delete any entries
//
/// If the key exists in the map, returns a reference to the corresponding
/// value, otherwise inserts a new entry in the map for that key
/// and returns a reference to the generated value.
///
/// Existing values are never overwritten.
///
/// The key may be any borrowed form of the map's key type, but
/// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
/// the key type.
///
/// # Example
/// ```
/// use elsa::index_map::FrozenIndexMap;
/// let map = FrozenIndexMap::new();
/// assert_eq!(map.insert(1, Box::new("a")), &"a");
/// assert_eq!(map.insert(1, Box::new("b")), &"a");
/// ```
pub fn insert(&self, k: K, v: V) -> &V::Target {
assert!(!self.in_use.get());
self.in_use.set(true);
Expand All @@ -47,6 +65,24 @@ impl<K: Eq + Hash, V: StableDeref, S: BuildHasher> FrozenIndexMap<K, V, S> {

// these should never return &K or &V
// these should never delete any entries
//
/// If the key exists in the map, returns a reference to the corresponding
/// value and its index, otherwise inserts a new entry in the map for that key
/// and returns a reference to the generated value and its index.
///
/// Existing values are never overwritten.
///
/// The key may be any borrowed form of the map's key type, but
/// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
/// the key type.
///
/// # Example
/// ```
/// use elsa::index_map::FrozenIndexMap;
/// let map = FrozenIndexMap::new();
/// assert_eq!(map.insert_full(12, Box::new("a")), (0, &"a"));
/// assert_eq!(map.insert_full(12, Box::new("b")), (0, &"a"));
/// ```
pub fn insert_full(&self, k: K, v: V) -> (usize, &V::Target) {
assert!(!self.in_use.get());
self.in_use.set(true);
Expand Down Expand Up @@ -91,6 +127,23 @@ impl<K: Eq + Hash, V: StableDeref, S: BuildHasher> FrozenIndexMap<K, V, S> {
ret
}

/// Returns a reference to the key-value mapping corresponding to an index.
///
/// The key may be any borrowed form of the map's key type, but
/// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
/// the key type.
///
/// # Examples
///
/// ```
/// use elsa::index_map::FrozenIndexMap;
///
/// let map = FrozenIndexMap::new();
/// let (idx, _ref) = map.insert_full(Box::new("foo"), Box::new("a"));
/// assert_eq!(idx, 0);
/// assert_eq!(map.get_index(idx), Some((&"foo", &"a")));
/// assert_eq!(map.get_index(idx + 1), None);
/// ```
pub fn get_index(&self, index: usize) -> Option<(&K::Target, &V::Target)>
where
K: StableDeref,
Expand Down
69 changes: 69 additions & 0 deletions src/index_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,24 @@ impl<T: Eq + Hash> FrozenIndexSet<T> {
impl<T: Eq + Hash + StableDeref, S: BuildHasher> FrozenIndexSet<T, S> {
// these should never return &T
// these should never delete any entries
//
/// If the value exists in the set, returns a reference to the corresponding
/// value, otherwise inserts a new entry in the set for that value
/// and returns a reference to it.
///
/// Existing values are never overwritten.
///
/// # Example
/// ```
/// use elsa::index_set::FrozenIndexSet;
/// let set = FrozenIndexSet::new();
/// let a_ref = set.insert(Box::new("a"));
/// let aa = "a";
/// let other_a_ref = unsafe { aa.as_ptr() as *const &str};
/// let other_a = Box::new(aa);
/// assert!(!std::ptr::eq(a_ref, other_a_ref));
/// assert!(std::ptr::eq(a_ref, set.insert(other_a)));
/// ```
pub fn insert(&self, value: T) -> &T::Target {
assert!(!self.in_use.get());
self.in_use.set(true);
Expand All @@ -45,6 +63,19 @@ impl<T: Eq + Hash + StableDeref, S: BuildHasher> FrozenIndexSet<T, S> {

// these should never return &T
// these should never delete any entries
/// If the key exists in the set, returns a reference to the corresponding
/// value and its index, otherwise inserts a new entry in the set for that value
/// and returns a reference to it and its index.
///
/// Existing values are never overwritten.
///
/// # Example
/// ```
/// use elsa::index_set::FrozenIndexSet;
/// let map = FrozenIndexSet::new();
/// assert_eq!(map.insert_full(Box::new("a")), (0, &"a"));
/// assert_eq!(map.insert_full(Box::new("b")), (1, &"b"));
/// ```
pub fn insert_full(&self, value: T) -> (usize, &T::Target) {
assert!(!self.in_use.get());
self.in_use.set(true);
Expand Down Expand Up @@ -84,6 +115,18 @@ impl<T: Eq + Hash + StableDeref, S: BuildHasher> FrozenIndexSet<T, S> {
// }
// }

/// Returns a reference to the value passed as argument if present in the set.
///
/// # Examples
///
/// ```
/// use elsa::index_set::FrozenIndexSet;
///
/// let set = FrozenIndexSet::new();
/// set.insert(Box::new("a"));
/// assert_eq!(set.get(&Box::new("a")), Some(&"a"));
/// assert_eq!(set.get(&Box::new("b")), None);
/// ```
pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&T::Target>
where
T: Borrow<Q>,
Expand All @@ -99,6 +142,19 @@ impl<T: Eq + Hash + StableDeref, S: BuildHasher> FrozenIndexSet<T, S> {
ret
}

/// Returns a reference to the value passed as argument if present in the set,
/// along with its index
///
/// # Examples
///
/// ```
/// use elsa::index_set::FrozenIndexSet;
///
/// let set = FrozenIndexSet::new();
/// set.insert(Box::new("a"));
/// assert_eq!(set.get_full(&Box::new("a")), Some((0, &"a")));
/// assert_eq!(set.get_full(&Box::new("b")), None);
/// ```
pub fn get_full<Q: ?Sized>(&self, k: &Q) -> Option<(usize, &T::Target)>
where
T: Borrow<Q>,
Expand All @@ -114,6 +170,19 @@ impl<T: Eq + Hash + StableDeref, S: BuildHasher> FrozenIndexSet<T, S> {
ret
}

/// Returns a reference to value at the index passed as argument, if
/// present in the set.
///
/// # Examples
///
/// ```
/// use elsa::index_set::FrozenIndexSet;
///
/// let set = FrozenIndexSet::new();
/// set.insert(Box::new("a"));
/// assert_eq!(set.get_index(0), Some(&"a"));
/// assert_eq!(set.get_index(1), None);
/// ```
pub fn get_index(&self, index: usize) -> Option<&T::Target> {
assert!(!self.in_use.get());
self.in_use.set(true);
Expand Down
102 changes: 102 additions & 0 deletions src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ use std::borrow::Borrow;
use std::cmp::Eq;
use std::collections::BTreeMap;
use std::collections::HashMap;
use std::fmt;
use std::hash::Hash;
use std::iter::{FromIterator, IntoIterator};
use std::ops::Index;

use std::sync::TryLockError;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::AtomicPtr;
use std::sync::atomic::AtomicUsize;
Expand All @@ -28,6 +30,28 @@ pub struct FrozenMap<K, V> {
map: RwLock<HashMap<K, V>>,
}

impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for FrozenMap<K, V> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.map.try_read() {
Ok(guard) => {
guard.fmt(f)
},
Err(TryLockError::Poisoned(err)) => {
f.debug_tuple("FrozenMap").field(&&**err.get_ref()).finish()
}
Err(TryLockError::WouldBlock) => {
struct LockedPlaceholder;
impl fmt::Debug for LockedPlaceholder {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("<locked>")
}
}
f.debug_tuple("FrozenMap").field(&LockedPlaceholder).finish()
},
}
}
}

impl<K, V> Default for FrozenMap<K, V> {
fn default() -> Self {
Self {
Expand All @@ -42,6 +66,15 @@ impl<K, V> FrozenMap<K, V> {
}
}

impl<T> From<Vec<T>> for FrozenVec<T> {
fn from(vec: Vec<T>) -> Self {
Self {
vec: RwLock::new(vec),
}
}
}


impl<K: Eq + Hash, V: StableDeref> FrozenMap<K, V> {
// these should never return &K or &V
// these should never delete any entries
Expand Down Expand Up @@ -396,6 +429,28 @@ pub struct FrozenVec<T> {
vec: RwLock<Vec<T>>,
}

impl<T: fmt::Debug> fmt::Debug for FrozenVec<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.vec.try_read() {
Ok(guard) => {
guard.fmt(f)
},
Err(TryLockError::Poisoned(err)) => {
f.debug_tuple("FrozenMap").field(&&**err.get_ref()).finish()
}
Err(TryLockError::WouldBlock) => {
struct LockedPlaceholder;
impl fmt::Debug for LockedPlaceholder {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("<locked>")
}
}
f.debug_tuple("FrozenMap").field(&LockedPlaceholder).finish()
},
}
}
}

impl<T> FrozenVec<T> {
/// Returns the number of elements in the vector.
pub fn len(&self) -> usize {
Expand Down Expand Up @@ -455,6 +510,53 @@ impl<T: StableDeref> FrozenVec<T> {
let vec = self.vec.read().unwrap();
unsafe { vec.get(index).map(|x| &*(&**x as *const T::Target)) }
}

/// Returns an iterator over the vector.
pub fn iter(&self) -> Iter<'_, T> {
self.into_iter()
}
}

/// Iterator over FrozenVec, obtained via `.iter()`
///
/// It is safe to push to the vector during iteration
#[derive(Debug)]
pub struct Iter<'a, T> {
vec: &'a FrozenVec<T>,
idx: usize,
}

impl<'a, T: StableDeref> Iterator for Iter<'a, T> {
type Item = &'a T::Target;
fn next(&mut self) -> Option<&'a T::Target> {
if let Some(ret) = self.vec.get(self.idx) {
self.idx += 1;
Some(ret)
} else {
None
}
}
}

impl<'a, T: StableDeref> IntoIterator for &'a FrozenVec<T> {
type Item = &'a T::Target;
type IntoIter = Iter<'a, T>;
fn into_iter(self) -> Iter<'a, T> {
Iter { vec: self, idx: 0 }
}
}

#[test]
fn test_iteration() {
let vec = vec!["a", "b", "c", "d"];
let frozen: FrozenVec<_> = vec.clone().into();

assert_eq!(vec, frozen.iter().collect::<Vec<_>>());
for (e1, e2) in vec.iter().zip(frozen.iter()) {
assert_eq!(*e1, e2);
}

assert_eq!(vec.len(), frozen.iter().count())
}

impl<T> FrozenVec<T> {
Expand Down

0 comments on commit a9ac01b

Please sign in to comment.