You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

227 lines
6.1 KiB

//! `smallmap` implementation of a referencing set.
//!
//! Uses the crate `smallmap` to store the hashes and is an optional feature of this crate.
use super::*;
use smallmap::{Collapse, Map};
/// A `smallmap` of referneces to items.
///
/// The usage is the same as `HashRefSet`, except it is backed by `smallmap` instead of a `HashSet`.
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature="serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SmallRefMap<T: ?Sized>(Map<HashType, ()>, PhantomData<Map<*const T, ()>>);
#[cfg(test)]
#[cfg(feature="serde")]
mod serde_tests
{
use super::*;
#[test]
fn ser_de()
{
let mut rmap = SmallRefMap::new();
rmap.insert("hello");
let string = serde_json::to_string(&rmap).expect("Ser failed");
println!("String {:?}", string);
let rmap2 = serde_json::from_str(&string[..]).expect("De failed)");
assert_eq!(rmap, rmap2);
}
}
unsafe impl<T: ?Sized + Send> Send for SmallRefMap<T>{}
unsafe impl<T: ?Sized + Send + Sync> Sync for SmallRefMap<T>{}
impl<T: ?Sized + Hash> SmallRefMap<T>
{
/// Creates a new empty `SmallRefMap`.
#[inline] pub fn new() -> Self
{
Self(Map::new(), PhantomData)
}
/// Consume into the inner `Map`.
pub fn into_inner(self) -> Map<HashType, ()>
{
self.0
}
/// Create a new `SmallRefMap` with this number of pages preallocated.
#[inline] pub fn with_capacity(pages: usize) -> Self
{
Self(Map::with_capacity(pages), PhantomData)
}
/// Insert a reference into the set. The reference can be any type that borrows to `T`.
///
/// Returns `true` if there was no previous item, `false` if there was.
pub fn insert<Q>(&mut self, value: &Q) -> bool
where Q: ?Sized + Borrow<T>
{
self.0.insert(compute_hash_for(value.borrow()), ()).is_none()
}
/// Remove a reference from the set.
///
/// Returns `true` if it existed.
pub fn remove<Q>(&mut self, value: &Q) -> bool
where Q: ?Sized + Borrow<T>
{
self.0.remove(&compute_hash_for(value.borrow())).is_some()
}
/// Check if this value has been inserted into the set.
pub fn contains<Q>(&mut self, value: &Q) -> bool
where Q: ?Sized + Borrow<T>
{
self.0.contains_key(&compute_hash_for(value.borrow()))
}
/// The number of items stored in the set
pub fn len(&self) -> usize
{
self.0.len()
}
/// Is the set empty
pub fn is_empty(&self) -> bool
{
self.0.iter().next().is_none()
}
/// An iterator over the hashes stored in the set.
pub fn hashes_iter(&self) -> Iter<'_, HashType>
{
Iter(self.0.iter())
}
#[inline] fn into_hashes_iter(self) -> IntoIter<HashType>
{
IntoIter(self.0.into_iter())
}
}
/// An iterator over the references to the hashes in `SmallRefMap`.
pub struct Iter<'a, T>(smallmap::iter::Iter<'a, T, ()>);
/// An iterator of the hashes inserted into `SmallRefMap`.
pub struct IntoIter<T>(smallmap::iter::IntoIter<T, ()>);
impl<'a, T: Collapse> Iterator for Iter<'a, T>
{
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item>
{
self.0.next().map(|x| &x.0)
}
fn size_hint(&self) -> (usize, Option<usize>)
{
self.0.size_hint()
}
}
impl<'a, T: Collapse> std::iter::FusedIterator for Iter<'a,T>{}
impl<'a, T: Collapse> Iterator for IntoIter<T>
{
type Item = T;
fn next(&mut self) -> Option<Self::Item>
{
self.0.next().map(|x| x.0)
}
fn size_hint(&self) -> (usize, Option<usize>)
{
self.0.size_hint()
}
}
impl<T: Collapse> std::iter::FusedIterator for IntoIter<T>{}
impl<T: Hash> IntoIterator for SmallRefMap<T>
{
type Item= HashType;
type IntoIter = IntoIter<HashType>;
fn into_iter(self) -> Self::IntoIter
{
self.into_hashes_iter()
}
}
#[cfg(test)]
mod tests
{
use super::*;
#[test]
fn insert()
{
let mut refset = SmallRefMap::new();
let values= vec![
"hi",
"hello",
"one",
"two",
];
for &string in values.iter()
{
refset.insert(string);
}
for string in values
{
assert!(refset.contains(string));
}
assert!(refset.insert("none"));
assert!(!refset.insert("two"));
}
#[cfg(nightly)]
mod benchmarks
{
use test::{black_box, Bencher};
const STRINGS: &str = "leo vel fringilla est ullamcorper eget nulla facilisi etiam dignissim diam quis enim lobortis scelerisque fermentum dui faucibus in ornare quam viverra orci sagittis eu volutpat odio facilisis mauris sit amet massa vitae tortor condimentum lacinia quis vel eros donec ac odio tempor orci dapibus ultrices in iaculis nunc sed augue lacus viverra vitae congue eu consequat ac felis donec et odio pellentesque diam volutpat commodo sed egestas egestas fringilla phasellus faucibus scelerisque eleifend donec pretium vulputate sapien nec sagittis aliquam malesuada bibendum arcu vitae elementum curabitur vitae nunc sed velit dignissim sodales ut eu sem integer vitae justo eget";
const INTS: &[u32] = &[182,248,69,225,164,219,73,122,14,205,148,221,24,107,209,83,210,87,148,249,234,181,217,154,180,240,132,145,208,15,77,4,117,16,43,1,95,49,150,18,207,161,107,216,215,100,76,198,43,21,99,177,77,28,29,172,117,136,151,96,66,208,244,138,90];
#[bench] fn non_owning_strings(b: &mut Bencher)
{
let strings: Vec<String> = STRINGS.split(char::is_whitespace).map(ToOwned::to_owned).collect();
let mut map = super::SmallRefMap::new();
b.iter(|| {
for string in strings.iter() {
black_box(map.insert(string.as_str()));
}
})
}
#[bench] fn owning_strings(b: &mut Bencher)
{
let strings: Vec<String> = STRINGS.split(char::is_whitespace).map(ToOwned::to_owned).collect();
let mut map = smallmap::Map::new();
b.iter(|| {
for string in strings.iter() {
black_box(map.insert(string.clone(), ())); //clone is needed here :/
}
})
}
#[bench] fn non_owning_ints(b: &mut Bencher)
{
let mut map = super::SmallRefMap::new();
b.iter(|| {
for int in INTS.iter() {
black_box(map.insert(int));
}
})
}
#[bench] fn owning_ints(b: &mut Bencher)
{
let mut map = smallmap::Map::new();
b.iter(|| {
for int in INTS.iter() {
black_box(map.insert(int, ()));
}
})
}
}
}