mirror of
https://github.com/Noratrieb/the-good-stuff.git
synced 2026-01-15 17:15:03 +01:00
move
This commit is contained in:
parent
1721d6a45a
commit
9bab547bcf
20 changed files with 1305 additions and 0 deletions
94
old-stuff/src/hashmaps/mod.rs
Normal file
94
old-stuff/src/hashmaps/mod.rs
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
use std::hash::{BuildHasher, Hash};
|
||||
|
||||
pub mod simple_open_addressing;
|
||||
|
||||
pub trait HashMapFamily {
|
||||
type Map<K, V, S>: HashMap<K, V, S>;
|
||||
}
|
||||
|
||||
pub trait HashMap<K, V, S>: IntoIterator<Item = (K, V)> {
|
||||
fn with_hasher(state: S) -> Self;
|
||||
|
||||
fn len(&self) -> usize;
|
||||
|
||||
fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
fn get(&self, key: &K) -> Option<&V>
|
||||
where
|
||||
K: Eq + Hash,
|
||||
S: BuildHasher;
|
||||
|
||||
fn insert(&mut self, key: K, value: V) -> Option<V>
|
||||
where
|
||||
K: Eq + Hash,
|
||||
S: BuildHasher;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::hash::{BuildHasher, BuildHasherDefault, Hasher, RandomState};
|
||||
|
||||
use super::{HashMap, HashMapFamily};
|
||||
|
||||
#[derive(Default)]
|
||||
struct CollidingHasher;
|
||||
impl Hasher for CollidingHasher {
|
||||
fn finish(&self) -> u64 {
|
||||
0
|
||||
}
|
||||
fn write(&mut self, _bytes: &[u8]) {}
|
||||
}
|
||||
|
||||
pub(super) fn run_tests<M>()
|
||||
where
|
||||
M: HashMapFamily,
|
||||
{
|
||||
let mk_str = || M::Map::<&str, &str, _>::with_hasher(RandomState::new());
|
||||
|
||||
let m = mk_str();
|
||||
assert_eq!(m.get(&"uwu"), None);
|
||||
assert_eq!(m.get(&"uwu"), None);
|
||||
|
||||
let mut m = mk_str();
|
||||
m.insert("hello", "world");
|
||||
assert_eq!(m.get(&"hello"), Some(&"world"));
|
||||
assert_eq!(m.len(), 1);
|
||||
m.insert("aaa", "yes");
|
||||
assert_eq!(m.get(&"hello"), Some(&"world"));
|
||||
assert_eq!(m.get(&"aaa"), Some(&"yes"));
|
||||
assert_eq!(m.len(), 2);
|
||||
|
||||
let mut m = mk_str();
|
||||
m.insert("hello", "world");
|
||||
assert_eq!(m.get(&"hello"), Some(&"world"));
|
||||
assert_eq!(m.len(), 1);
|
||||
m.insert("hello", "no");
|
||||
assert_eq!(m.get(&"hello"), Some(&"no"));
|
||||
assert_eq!(m.len(), 1);
|
||||
|
||||
for count in [1, 10, 100, 1000, 10_000, 100_000] {
|
||||
test_many::<M, _>(count, RandomState::new());
|
||||
}
|
||||
test_many::<M, _>(1000, BuildHasherDefault::<CollidingHasher>::default());
|
||||
}
|
||||
|
||||
fn test_many<M: HashMapFamily, H: BuildHasher>(count: usize, h: H) {
|
||||
let mut m = M::Map::with_hasher(h);
|
||||
|
||||
for i in 0..count {
|
||||
m.insert(i, i);
|
||||
}
|
||||
|
||||
let mut found = vec![false; count];
|
||||
for (k, v) in m.into_iter() {
|
||||
assert_eq!(k, v);
|
||||
assert!(!found[k], "duplicate element");
|
||||
found[k] = true;
|
||||
}
|
||||
for (i, found) in found.iter().enumerate() {
|
||||
assert!(found, "element {i} was lost");
|
||||
}
|
||||
}
|
||||
}
|
||||
151
old-stuff/src/hashmaps/simple_open_addressing.rs
Normal file
151
old-stuff/src/hashmaps/simple_open_addressing.rs
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
use super::{HashMap, HashMapFamily};
|
||||
use std::{
|
||||
hash::{BuildHasher, Hash, RandomState},
|
||||
vec,
|
||||
};
|
||||
|
||||
type Entry<K, V> = Option<(K, V)>;
|
||||
|
||||
pub struct SimpleOAHashMap<K, V, S = RandomState> {
|
||||
buckets: Vec<Entry<K, V>>,
|
||||
filled: usize,
|
||||
s: S,
|
||||
}
|
||||
|
||||
impl<K: Eq + Hash, V> SimpleOAHashMap<K, V, RandomState> {
|
||||
pub fn new() -> Self {
|
||||
Self::with_hasher(RandomState::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Eq + Hash, V, S: BuildHasher> SimpleOAHashMap<K, V, S> {
|
||||
fn bucket_of_elem(&self, key: &K) -> usize {
|
||||
assert_ne!(self.buckets.len(), 0, "cannot compute bucket of empty map");
|
||||
let hash = self.s.hash_one(&key) as usize;
|
||||
hash % self.buckets.len()
|
||||
}
|
||||
|
||||
fn grow(&mut self) {
|
||||
let len = self.buckets.len();
|
||||
let new = if len == 0 { 8 } else { len * 2 };
|
||||
let old = IntoIter::new(std::mem::take(&mut self.buckets));
|
||||
let new_buckets = (0..new).map(|_| None).collect();
|
||||
self.buckets = new_buckets;
|
||||
self.extend(old);
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Eq + Hash, V, S: BuildHasher> Extend<(K, V)> for SimpleOAHashMap<K, V, S> {
|
||||
fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
|
||||
iter.into_iter()
|
||||
.for_each(|(key, value)| drop(self.insert(key, value)));
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V, S> super::HashMap<K, V, S> for SimpleOAHashMap<K, V, S> {
|
||||
fn with_hasher(state: S) -> Self {
|
||||
Self {
|
||||
buckets: Vec::new(),
|
||||
filled: 0,
|
||||
s: state,
|
||||
}
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
self.filled
|
||||
}
|
||||
|
||||
fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
fn get(&self, key: &K) -> Option<&V>
|
||||
where
|
||||
K: Eq + Hash,
|
||||
S: BuildHasher,
|
||||
{
|
||||
if self.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let bucket = self.bucket_of_elem(&key);
|
||||
|
||||
let result = self.buckets[bucket..]
|
||||
.iter()
|
||||
.take_while(|elem| elem.is_some())
|
||||
.find(|elem| matches!(elem, Some((elem_key, _)) if elem_key == key));
|
||||
|
||||
if let Some(Some((_, value))) = result {
|
||||
Some(value)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn insert(&mut self, key: K, value: V) -> Option<V>
|
||||
where
|
||||
K: Eq + Hash,
|
||||
S: BuildHasher,
|
||||
{
|
||||
if self.filled >= self.buckets.len() {
|
||||
self.grow();
|
||||
}
|
||||
loop {
|
||||
let bucket = self.bucket_of_elem(&key);
|
||||
let bucket = self.buckets[bucket..].iter_mut().find(|bucket| {
|
||||
bucket.is_none() || matches!(bucket, Some((elem_key, _)) if *elem_key == key)
|
||||
});
|
||||
if let Some(bucket) = bucket {
|
||||
if bucket.is_none() {
|
||||
self.filled += 1;
|
||||
}
|
||||
let before = std::mem::replace(bucket, Some((key, value)));
|
||||
return before.map(|(_, v)| v);
|
||||
} else {
|
||||
self.grow();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IntoIter<K, V> {
|
||||
buckets: std::iter::FilterMap<vec::IntoIter<Entry<K, V>>, fn(Entry<K, V>) -> Option<(K, V)>>,
|
||||
}
|
||||
|
||||
impl<K, V> IntoIter<K, V> {
|
||||
fn new(buckets: Vec<Entry<K, V>>) -> Self {
|
||||
IntoIter {
|
||||
buckets: buckets.into_iter().filter_map(std::convert::identity),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> Iterator for IntoIter<K, V> {
|
||||
type Item = (K, V);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.buckets.next()
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V, S> IntoIterator for SimpleOAHashMap<K, V, S> {
|
||||
type Item = (K, V);
|
||||
|
||||
type IntoIter = IntoIter<K, V>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
IntoIter::new(self.buckets)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SimpleOAHashMapFamily;
|
||||
impl HashMapFamily for SimpleOAHashMapFamily {
|
||||
type Map<K, V, S> = SimpleOAHashMap<K, V, S>;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn do_tests() {
|
||||
crate::hashmaps::tests::run_tests::<super::SimpleOAHashMapFamily>();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue