use std::{
borrow::Borrow,
collections::HashMap,
fmt::{self, Debug, Formatter},
hash::{BuildHasher, Hash, Hasher, RandomState},
iter::FusedIterator,
marker::PhantomData,
mem::MaybeUninit,
ptr::{self, NonNull},
};
use serde::{
de::{Deserialize, Deserializer, SeqAccess, Visitor},
ser::{Serialize, SerializeSeq, Serializer},
};
pub struct HashList<T, S = RandomState> {
map: HashMap<DataRef<T>, NonNull<Entry<T>>, S>,
head: *mut Entry<T>,
tail: *mut Entry<T>,
}
struct Entry<T> {
data: MaybeUninit<T>,
prev: *mut Entry<T>,
next: *mut Entry<T>,
}
struct DataRef<T> {
data: *const T,
}
#[repr(transparent)]
struct KeyWrapper<K>(K);
pub struct Iter<'a, T, S> {
list: &'a HashList<T, S>,
head: *mut Entry<T>,
tail: *mut Entry<T>,
}
pub struct IntoIter<T, S> {
list: HashList<T, S>,
}
impl<T, S> HashList<T, S>
where
T: Eq + Hash,
S: BuildHasher,
{
#[inline]
pub fn front(&self) -> Option<&T> {
if self.head.is_null() {
return None;
}
let data = unsafe { (*self.head).data.assume_init_ref() };
Some(data)
}
#[inline]
pub fn back(&self) -> Option<&T> {
if self.tail.is_null() {
return None;
}
let data = unsafe { (*self.tail).data.assume_init_ref() };
Some(data)
}
#[inline]
pub fn contains<K>(&self, key: &K) -> bool
where
T: Borrow<K>,
K: Eq + Hash,
{
self.map.contains_key(KeyWrapper::from_ref(key))
}
#[inline]
pub fn push_front(&mut self, data: T) -> Option<T> {
let maybe_old_data = self
.map
.remove(&DataRef::from_ref(&data))
.map(|old_entry| {
let old_entry_ptr = old_entry.as_ptr();
self.detach(old_entry_ptr);
Entry::<T>::into_data(old_entry_ptr)
});
let entry = Entry::<T>::new(data);
let entry_ptr = entry.as_ptr();
self.attach_front(entry_ptr);
let data_ref = DataRef::from_entry_ptr(entry_ptr);
self.map.insert(data_ref, entry);
maybe_old_data
}
#[inline]
pub fn push_back(&mut self, data: T) -> Option<T> {
let maybe_old_data = self
.map
.remove(&DataRef::from_ref(&data))
.map(|old_entry| {
let old_entry_ptr = old_entry.as_ptr();
self.detach(old_entry_ptr);
Entry::<T>::into_data(old_entry_ptr)
});
let entry = Entry::<T>::new(data);
let entry_ptr = entry.as_ptr();
self.attach_back(entry_ptr);
let data_ref = DataRef::from_entry_ptr(entry_ptr);
self.map.insert(data_ref, entry);
maybe_old_data
}
#[inline]
pub fn move_front<K>(&mut self, key: &K)
where
T: Borrow<K>,
K: Eq + Hash,
{
let Some(entry_ref) = self.map.get(KeyWrapper::from_ref(key)) else {
return;
};
let entry_ptr = entry_ref.as_ptr();
if ptr::eq(self.head, entry_ptr) {
return;
}
self.detach(entry_ptr);
self.attach_front(entry_ptr);
}
#[inline]
pub fn move_back<K>(&mut self, key: &K)
where
T: Borrow<K>,
K: Eq + Hash,
{
let Some(entry_ref) = self.map.get(KeyWrapper::from_ref(key)) else {
return;
};
let entry_ptr = entry_ref.as_ptr();
if ptr::eq(self.tail, entry_ptr) {
return;
}
self.detach(entry_ptr);
self.attach_back(entry_ptr);
}
#[inline]
pub fn pop_front(&mut self) -> Option<T> {
if self.head.is_null() {
return None;
}
let entry_ptr = self.head;
self.detach(entry_ptr);
let data_ref = DataRef::from_entry_ptr(entry_ptr);
self.map.remove(&data_ref).unwrap();
Some(Entry::<T>::into_data(entry_ptr))
}
#[inline]
pub fn pop_back(&mut self) -> Option<T> {
if self.tail.is_null() {
return None;
}
let entry_ptr = self.tail;
self.detach(entry_ptr);
let data_ref = DataRef::from_entry_ptr(entry_ptr);
self.map.remove(&data_ref).unwrap();
Some(Entry::<T>::into_data(entry_ptr))
}
#[inline]
pub fn get<K>(&self, key: &K) -> Option<&T>
where
T: Borrow<K>,
K: Eq + Hash,
{
let entry = self.map.get(KeyWrapper::from_ref(key))?;
let entry_ptr = entry.as_ptr();
let data = unsafe { (*entry_ptr).data.assume_init_ref() };
Some(data)
}
#[inline]
pub fn before<K>(&self, key: &K) -> Option<&T>
where
T: Borrow<K>,
K: Eq + Hash,
{
let entry = self.map.get(KeyWrapper::from_ref(key))?;
let entry_ptr = entry.as_ptr();
let prev_ptr = unsafe { (*entry_ptr).prev };
if prev_ptr.is_null() {
return None;
}
let data = unsafe { (*prev_ptr).data.assume_init_ref() };
Some(data)
}
#[inline]
pub fn after<K>(&self, key: &K) -> Option<&T>
where
T: Borrow<K>,
K: Eq + Hash,
{
let entry = self.map.get(KeyWrapper::from_ref(key))?;
let entry_ptr = entry.as_ptr();
let next_ptr = unsafe { (*entry_ptr).next };
if next_ptr.is_null() {
return None;
}
let data = unsafe { (*next_ptr).data.assume_init_ref() };
Some(data)
}
#[inline]
pub fn update<K, F>(&mut self, key: &K, mut f: F)
where
T: Borrow<K>,
K: Eq + Hash,
F: FnMut(&mut T),
{
let Some(entry) = self.map.remove(KeyWrapper::from_ref(key)) else {
return;
};
let entry_ptr = entry.as_ptr();
let data = unsafe { &mut *(*entry_ptr).data.as_mut_ptr() };
f(data);
let data_ref = DataRef::from_ref(data);
self.map.insert(data_ref, entry);
}
#[inline]
pub fn remove<K>(&mut self, key: &K) -> Option<T>
where
T: Borrow<K>,
K: Eq + Hash,
{
let entry = self.map.remove(KeyWrapper::from_ref(key))?;
let entry_ptr = entry.as_ptr();
self.detach(entry_ptr);
Some(Entry::<T>::into_data(entry_ptr))
}
#[inline]
pub fn clear(&mut self) {
while self.pop_front().is_some() {}
}
fn attach_front(&mut self, entry_ptr: *mut Entry<T>) {
unsafe {
(*entry_ptr).next = self.head;
}
if !self.head.is_null() {
unsafe {
(*self.head).prev = entry_ptr;
}
}
self.head = entry_ptr;
if self.tail.is_null() {
self.tail = entry_ptr;
}
}
fn attach_back(&mut self, entry_ptr: *mut Entry<T>) {
unsafe {
(*entry_ptr).prev = self.tail;
}
if !self.tail.is_null() {
unsafe {
(*self.tail).next = entry_ptr;
}
}
self.tail = entry_ptr;
if self.head.is_null() {
self.head = entry_ptr;
}
}
fn detach(&mut self, entry_ptr: *mut Entry<T>) {
let prev = unsafe { (*entry_ptr).prev };
let next = unsafe { (*entry_ptr).next };
if !prev.is_null() {
unsafe {
(*prev).next = next;
}
}
if !next.is_null() {
unsafe {
(*next).prev = prev;
}
}
if ptr::eq(self.head, entry_ptr) {
self.head = next;
}
if ptr::eq(self.tail, entry_ptr) {
self.tail = prev;
}
unsafe {
(*entry_ptr).next = ptr::null_mut();
(*entry_ptr).prev = ptr::null_mut();
}
}
}
impl<T, S> HashList<T, S> {
#[inline]
pub fn with_hasher(hasher: S) -> Self {
HashList {
map: HashMap::with_hasher(hasher),
head: ptr::null_mut(),
tail: ptr::null_mut(),
}
}
#[inline]
pub fn is_empty(&self) -> bool {
self.map.is_empty()
}
#[inline]
pub fn len(&self) -> usize {
self.map.len()
}
#[inline]
pub fn iter(&self) -> Iter<'_, T, S> {
Iter {
list: self,
head: self.head,
tail: self.tail,
}
}
}
impl<T> HashList<T, RandomState> {
#[inline]
pub fn new() -> Self {
HashList::with_hasher(RandomState::new())
}
}
impl<T, S> Default for HashList<T, S>
where
S: Default,
{
fn default() -> Self {
HashList::<T, S>::with_hasher(S::default())
}
}
impl<T, S> PartialEq for HashList<T, S>
where
T: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.len() == other.len() && self.iter().eq(other.iter())
}
}
impl<T, S> Eq for HashList<T, S> where T: Eq {}
impl<T> Entry<T> {
fn new(data: T) -> NonNull<Self> {
let entry = Entry {
data: MaybeUninit::new(data),
prev: ptr::null_mut(),
next: ptr::null_mut(),
};
let boxed = Box::new(entry);
unsafe { NonNull::new_unchecked(Box::into_raw(boxed)) }
}
fn into_data(entry_ptr: *mut Entry<T>) -> T {
unsafe {
let entry = *Box::from_raw(entry_ptr);
entry.data.assume_init()
}
}
}
impl<T> DataRef<T> {
fn from_ref(data: &T) -> Self {
DataRef {
data,
}
}
fn from_entry_ptr(entry_ptr: *mut Entry<T>) -> Self {
let data_ptr = unsafe { (*entry_ptr).data.as_ptr() };
DataRef {
data: data_ptr
}
}
}
impl<T> Hash for DataRef<T>
where
T: Hash,
{
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
unsafe { (*self.data).hash(state) }
}
}
impl<T> PartialEq for DataRef<T>
where
T: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
unsafe { (*self.data).eq(&*other.data) }
}
}
impl<T> Eq for DataRef<T> where T: Eq {}
impl<K> KeyWrapper<K> {
fn from_ref(key: &K) -> &Self {
unsafe { &*(key as *const K as *const KeyWrapper<K>) }
}
}
impl<K> Hash for KeyWrapper<K>
where
K: Hash,
{
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.0.hash(state)
}
}
impl<K> PartialEq for KeyWrapper<K>
where
K: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.0.eq(&other.0)
}
}
impl<K> Eq for KeyWrapper<K> where K: Eq {}
impl<K, T> Borrow<KeyWrapper<K>> for DataRef<T>
where
T: Borrow<K>,
{
fn borrow(&self) -> &KeyWrapper<K> {
let data_ref = unsafe { &*self.data }.borrow();
KeyWrapper::from_ref(data_ref)
}
}
impl<'a, T, S> Iterator for Iter<'a, T, S> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
if self.head.is_null() {
return None;
}
let prev = unsafe { (*self.head).prev };
if ptr::eq(prev, self.tail) {
return None;
}
let data = unsafe { (*self.head).data.assume_init_ref() };
unsafe {
self.head = (*self.head).next;
}
Some(data)
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.list.len(), Some(self.list.len()))
}
}
impl<T, S> DoubleEndedIterator for Iter<'_, T, S> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.tail.is_null() {
return None;
}
let next = unsafe { (*self.tail).next };
if ptr::eq(next, self.head) {
return None;
}
let data = unsafe { (*self.tail).data.assume_init_ref() };
unsafe {
self.tail = (*self.tail).prev;
}
Some(data)
}
}
impl<'a, T, S> IntoIterator for &'a HashList<T, S>
where
T: Eq + Hash,
S: BuildHasher,
{
type Item = &'a T;
type IntoIter = Iter<'a, T, S>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<T, S> Iterator for IntoIter<T, S>
where
T: Eq + Hash,
S: BuildHasher,
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.list.pop_front()
}
}
impl<T, S> DoubleEndedIterator for IntoIter<T, S>
where
T: Eq + Hash,
S: BuildHasher,
{
fn next_back(&mut self) -> Option<Self::Item> {
self.list.pop_back()
}
}
impl<T, S> ExactSizeIterator for Iter<'_, T, S>
where
T: Eq + Hash,
S: BuildHasher,
{
}
impl<T, S> ExactSizeIterator for IntoIter<T, S>
where
T: Eq + Hash,
S: BuildHasher,
{
}
impl<T, S> FusedIterator for Iter<'_, T, S>
where
T: Eq + Hash,
S: BuildHasher,
{
}
impl<T, S> FusedIterator for IntoIter<T, S>
where
T: Eq + Hash,
S: BuildHasher,
{
}
impl<T, S> IntoIterator for HashList<T, S>
where
T: Eq + Hash,
S: BuildHasher,
{
type Item = T;
type IntoIter = IntoIter<T, S>;
fn into_iter(self) -> Self::IntoIter {
IntoIter {
list: self
}
}
}
impl<T, S> FromIterator<T> for HashList<T, S>
where
T: Eq + Hash,
S: Default + BuildHasher,
{
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = T>,
{
let mut list = HashList::<T, S>::default();
for value in iter {
list.push_back(value);
}
list
}
}
impl<T, S> Extend<T> for HashList<T, S>
where
T: Eq + Hash,
S: BuildHasher,
{
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = T>,
{
for value in iter {
self.push_back(value);
}
}
}
impl<T, S> Hash for HashList<T, S>
where
T: Eq + Hash,
S: BuildHasher,
{
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.len().hash(state);
for value in self {
value.hash(state);
}
}
}
impl<T, S> Debug for HashList<T, S>
where
T: Eq + Hash + Debug,
S: BuildHasher,
{
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
fmt.write_str("HashList(")?;
fmt.debug_list().entries(self).finish()?;
fmt.write_str(")")?;
Ok(())
}
}
impl<T, S> Drop for HashList<T, S> {
fn drop(&mut self) {
self.map.drain().for_each(|(_, entry)| unsafe {
let mut entry = *Box::from_raw(entry.as_ptr());
ptr::drop_in_place(entry.data.as_mut_ptr());
});
}
}
impl<T, S> Serialize for HashList<T, S>
where
T: Eq + Hash + Serialize,
S: BuildHasher,
{
fn serialize<Se>(&self, serializer: Se) -> Result<Se::Ok, Se::Error>
where
Se: Serializer,
{
let mut seq = serializer.serialize_seq(Some(self.len()))?;
for value in self {
seq.serialize_element(value)?;
}
seq.end()
}
}
struct HashListVisitor<T, S> {
marker: PhantomData<(T, S)>,
}
impl<'de, T, S> Visitor<'de> for HashListVisitor<T, S>
where
T: Eq + Hash + Deserialize<'de>,
S: Default + BuildHasher,
{
type Value = HashList<T, S>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a hash list")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let mut list = HashList::<T, S>::default();
while let Some(value) = seq.next_element()? {
list.push_back(value);
}
Ok(list)
}
}
impl<'de, T, S> Deserialize<'de> for HashList<T, S>
where
T: Eq + Hash + Deserialize<'de>,
S: Default + BuildHasher,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let visitor = HashListVisitor {
marker: PhantomData,
};
deserializer.deserialize_seq(visitor)
}
}
unsafe impl<T, S> Send for HashList<T, S> {}
unsafe impl<T, S> Sync for HashList<T, S> {}
#[cfg(test)]
mod tests {
use std::{
borrow::Borrow,
hash::{Hash, Hasher},
};
use droptest::{DropGuard, DropRegistry, assert_drop, assert_no_drop};
use serde_test::{Token, assert_tokens};
use crate::collections::HashList;
struct DroppableObject<'a> {
id: u64,
guard: DropGuard<'a, ()>,
}
#[test]
fn it_pushes_front_correctly() {
let mut list = HashList::<u32>::default();
let values = vec![1, 2, 3, 4];
for value in &values {
list.push_front(*value);
}
for (index, value) in list.iter().enumerate() {
assert_eq!(*value, values[values.len() - index - 1]);
}
}
#[test]
fn it_pushes_back_correctly() {
let mut list = HashList::<u32>::default();
let values = vec![1, 2, 3, 4];
for value in &values {
list.push_back(*value);
}
for (index, value) in list.iter().enumerate() {
assert_eq!(*value, values[index]);
}
}
#[test]
fn it_moves_front_correctly() {
let mut list = HashList::<u32>::default();
let values = vec![1, 2, 3, 4];
for value in &values {
list.push_back(*value);
}
list.move_front(&2);
let expected = [2, 1, 3, 4];
for (index, value) in list.iter().enumerate() {
assert_eq!(*value, expected[index]);
}
}
#[test]
fn it_moves_back_correctly() {
let mut list = HashList::<u32>::default();
let values = vec![1, 2, 3, 4];
for value in &values {
list.push_back(*value);
}
list.move_back(&2);
let expected = [1, 3, 4, 2];
for (index, value) in list.iter().enumerate() {
assert_eq!(*value, expected[index]);
}
}
#[test]
fn it_pops_front_correctly() {
let mut list = HashList::<u32>::default();
let mut values = vec![1, 2, 3, 4];
for value in &values {
list.push_back(*value);
}
assert_eq!(list.pop_front(), Some(1));
values.remove(0);
for (index, value) in list.iter().enumerate() {
assert_eq!(*value, values[index]);
}
}
#[test]
fn it_pops_back_correctly() {
let mut list = HashList::<u32>::default();
let mut values = vec![1, 2, 3, 4];
for value in &values {
list.push_back(*value);
}
assert_eq!(list.pop_back(), Some(4));
values.remove(3);
for (index, value) in list.iter().enumerate() {
assert_eq!(*value, values[index]);
}
}
#[test]
fn it_iterates_correctly() {
let list: HashList<u32> = [1, 2, 3].into_iter().collect();
let mut iter = list.iter();
assert_eq!(iter.next(), Some(&1));
assert_eq!(iter.next(), Some(&2));
assert_eq!(iter.next(), Some(&3));
assert_eq!(iter.next(), None);
let mut iter = list.into_iter();
assert_eq!(iter.next(), Some(1));
assert_eq!(iter.next(), Some(2));
assert_eq!(iter.next(), Some(3));
assert_eq!(iter.next(), None);
}
#[test]
fn it_reverse_iterates_correctly() {
let list: HashList<u32> = [1, 2, 3, 4, 5, 6].into_iter().collect();
let mut iter = list.iter();
assert_eq!(iter.next(), Some(&1));
assert_eq!(iter.next_back(), Some(&6));
assert_eq!(iter.next_back(), Some(&5));
assert_eq!(iter.next(), Some(&2));
assert_eq!(iter.next(), Some(&3));
assert_eq!(iter.next(), Some(&4));
assert_eq!(iter.next(), None);
assert_eq!(iter.next_back(), None);
let mut iter = list.into_iter();
assert_eq!(iter.next(), Some(1));
assert_eq!(iter.next_back(), Some(6));
assert_eq!(iter.next_back(), Some(5));
assert_eq!(iter.next(), Some(2));
assert_eq!(iter.next(), Some(3));
assert_eq!(iter.next(), Some(4));
assert_eq!(iter.next(), None);
assert_eq!(iter.next_back(), None);
}
#[test]
fn it_drops_removed_object() {
let registry = DropRegistry::default();
let mut list = HashList::<DroppableObject>::default();
let object1 = DroppableObject::new(®istry, 1);
let object2 = DroppableObject::new(®istry, 2);
let object1_guard_id = object1.guard.id();
let object2_guard_id = object2.guard.id();
list.push_front(object1);
list.push_front(object2);
list.remove(&1);
assert_drop!(registry, object1_guard_id);
assert_no_drop!(registry, object2_guard_id);
}
#[test]
fn it_drops_front_popped_object() {
let registry = DropRegistry::default();
let mut list = HashList::<DroppableObject>::default();
let object1 = DroppableObject::new(®istry, 1);
let object2 = DroppableObject::new(®istry, 2);
let object1_guard_id = object1.guard.id();
let object2_guard_id = object2.guard.id();
list.push_front(object1);
list.push_front(object2);
list.pop_front();
assert_no_drop!(registry, object1_guard_id);
assert_drop!(registry, object2_guard_id);
}
#[test]
fn it_drops_back_popped_object() {
let registry = DropRegistry::default();
let mut list = HashList::<DroppableObject>::default();
let object1 = DroppableObject::new(®istry, 1);
let object2 = DroppableObject::new(®istry, 2);
let object1_guard_id = object1.guard.id();
let object2_guard_id = object2.guard.id();
list.push_front(object1);
list.push_front(object2);
list.pop_back();
assert_drop!(registry, object1_guard_id);
assert_no_drop!(registry, object2_guard_id);
}
#[test]
fn it_drops_front_replaced_object() {
let registry = DropRegistry::default();
let mut list = HashList::<DroppableObject>::default();
let object1 = DroppableObject::new(®istry, 1);
let object2 = DroppableObject::new(®istry, 1);
let object1_guard_id = object1.guard.id();
let object2_guard_id = object2.guard.id();
list.push_front(object1);
list.push_front(object2);
assert_drop!(registry, object1_guard_id);
assert_no_drop!(registry, object2_guard_id);
}
#[test]
fn it_drops_back_replaced_object() {
let registry = DropRegistry::default();
let mut list = HashList::<DroppableObject>::default();
let object1 = DroppableObject::new(®istry, 1);
let object2 = DroppableObject::new(®istry, 1);
let object1_guard_id = object1.guard.id();
let object2_guard_id = object2.guard.id();
list.push_back(object1);
list.push_back(object2);
assert_drop!(registry, object1_guard_id);
assert_no_drop!(registry, object2_guard_id);
}
#[test]
fn it_drops_cleared_objects() {
let registry = DropRegistry::default();
let mut list = HashList::<DroppableObject>::default();
let object1 = DroppableObject::new(®istry, 1);
let object2 = DroppableObject::new(®istry, 2);
let object1_guard_id = object1.guard.id();
let object2_guard_id = object2.guard.id();
list.push_front(object1);
list.push_front(object2);
list.clear();
assert_drop!(registry, object1_guard_id);
assert_drop!(registry, object2_guard_id);
}
#[test]
fn it_ser_de_empty() {
let list = HashList::<u32>::default();
assert_tokens(&list, &[
Token::Seq {
len: Some(0)
},
Token::SeqEnd,
]);
}
#[test]
fn it_ser_de() {
let list: HashList<u32> = [1, 2, 3, 4, 5, 6].into_iter().collect();
assert_tokens(&list, &[
Token::Seq {
len: Some(6)
},
Token::U32(1),
Token::U32(2),
Token::U32(3),
Token::U32(4),
Token::U32(5),
Token::U32(6),
Token::SeqEnd,
]);
}
impl<'a> DroppableObject<'a> {
fn new(registry: &'a DropRegistry, id: u64) -> Self {
DroppableObject {
id,
guard: registry.new_guard(),
}
}
}
impl PartialEq for DroppableObject<'_> {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl Eq for DroppableObject<'_> {}
impl Borrow<u64> for DroppableObject<'_> {
fn borrow(&self) -> &u64 {
&self.id
}
}
impl Hash for DroppableObject<'_> {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.id.hash(state)
}
}
}