use crate::error::Result;
use crate::hash_map::ZiporaHashMap;
use std::hash::Hash;
use std::marker::PhantomData;
#[derive(Debug)]
pub struct EasyHashMap<K, V>
where
K: Hash + Eq + Clone,
V: Clone,
{
inner: ZiporaHashMap<K, V>,
default_value: Option<V>,
auto_grow: bool,
max_load_factor: f64,
}
impl<K, V> EasyHashMap<K, V>
where
K: Hash + Eq + Clone,
V: Clone,
{
pub fn new() -> Self {
Self {
inner: ZiporaHashMap::new().unwrap_or_default(),
default_value: None,
auto_grow: true,
max_load_factor: 0.75,
}
}
pub fn with_default(default_value: V) -> Self {
Self {
inner: ZiporaHashMap::new().unwrap_or_default(),
default_value: Some(default_value),
auto_grow: true,
max_load_factor: 0.75,
}
}
pub fn put(&mut self, key: K, value: V) {
if self.auto_grow && self.should_grow() {
let current_capacity = self.inner.capacity();
let new_capacity = (current_capacity * 2).max(64);
if let Ok(mut new_map) = ZiporaHashMap::with_capacity(new_capacity) {
let entries_to_copy = self.get_all_entries();
for (k, v) in entries_to_copy {
let _ = new_map.insert(k, v);
}
self.inner = new_map;
}
}
let _ = self.inner.insert(key, value);
}
#[inline]
pub fn get(&self, key: &K) -> Option<&V> {
self.inner.get(key)
}
pub fn get_or_default(&self, key: &K) -> &V {
self.inner
.get(key)
.unwrap_or_else(|| self.default_value.as_ref().expect("No default value set"))
}
pub fn get_or_insert(&mut self, key: K, value: V) -> Result<&mut V> {
let key_exists = self.inner.contains_key(&key);
if !key_exists {
self.put(key.clone(), value);
}
Ok(self
.inner
.get_mut(&key)
.expect("Key should exist after insertion"))
}
pub fn get_or_insert_with<F>(&mut self, key: K, f: F) -> Result<&mut V>
where
F: FnOnce() -> V,
{
let key_exists = self.inner.contains_key(&key);
if !key_exists {
let value = f();
self.put(key.clone(), value);
}
Ok(self
.inner
.get_mut(&key)
.expect("Key should exist after insertion"))
}
pub fn remove(&mut self, key: &K) -> Option<V> {
self.inner.remove(key)
}
pub fn contains_key(&self, key: &K) -> bool {
self.inner.contains_key(key)
}
#[inline]
pub fn len(&self) -> usize {
self.inner.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
#[inline]
pub fn capacity(&self) -> usize {
self.inner.capacity()
}
pub fn clear(&mut self) {
self.inner.clear();
}
pub fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) {
for (key, value) in iter {
self.put(key, value);
}
}
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(&K, &mut V) -> bool,
{
let keys_to_remove: Vec<K> = self
.inner
.iter()
.filter_map(|(k, v)| {
let mut value_copy = v.clone();
if f(k, &mut value_copy) {
None
} else {
Some(k.clone())
}
})
.collect();
for key in keys_to_remove {
self.inner.remove(&key);
}
}
pub fn set_auto_grow(&mut self, enabled: bool) {
self.auto_grow = enabled;
}
pub fn set_max_load_factor(&mut self, factor: f64) {
self.max_load_factor = factor.clamp(0.1, 0.95);
}
pub fn initial_capacity(capacity: usize) -> EasyHashMapBuilder<K, V>
where
K: Hash + Eq + Clone,
V: Clone,
{
EasyHashMapBuilder::new().with_capacity(capacity)
}
pub fn with_default_value(default: V) -> EasyHashMapBuilder<K, V>
where
K: Hash + Eq + Clone,
V: Clone,
{
EasyHashMapBuilder::new().with_default(default)
}
fn should_grow(&self) -> bool {
let capacity = self.inner.capacity();
if capacity == 0 {
return true;
}
let load_factor = self.inner.len() as f64 / capacity as f64;
load_factor >= self.max_load_factor
}
fn get_all_entries(&self) -> Vec<(K, V)> {
let mut entries = Vec::new();
for (k, v) in self.inner.iter() {
entries.push((k.clone(), v.clone()));
}
entries
}
pub fn try_reserve(&mut self, _additional: usize) -> Result<()> {
Ok(())
}
pub fn reserve(&mut self, additional: usize) {
let _ = self.try_reserve(additional);
}
pub fn shrink_to_fit(&mut self) {
let current_len = self.inner.len();
let current_capacity = self.inner.capacity();
if current_len < current_capacity / 2 && current_capacity > 32 {
let entries: Vec<(K, V)> = self.inner.iter().map(|(k, v)| (k.clone(), v.clone())).collect();
let new_capacity = (current_len * 2).max(16);
if let Ok(mut new_map) = ZiporaHashMap::with_capacity(new_capacity) {
for (key, value) in entries {
let _ = new_map.insert(key, value);
}
self.inner = new_map;
}
}
}
pub fn statistics(&self) -> EasyHashMapStats {
EasyHashMapStats {
len: self.len(),
capacity: self.capacity(),
load_factor: if self.capacity() > 0 {
self.len() as f64 / self.capacity() as f64
} else {
0.0
},
has_default: self.default_value.is_some(),
auto_grow_enabled: self.auto_grow,
max_load_factor: self.max_load_factor,
}
}
}
#[derive(Debug)]
pub struct EasyHashMapBuilder<K, V>
where
K: Hash + Eq + Clone,
V: Clone,
{
capacity: usize,
default_value: Option<V>,
auto_grow: bool,
max_load_factor: f64,
_phantom: PhantomData<K>,
}
impl<K, V> EasyHashMapBuilder<K, V>
where
K: Hash + Eq + Clone,
V: Clone,
{
pub fn new() -> Self {
Self {
capacity: 16,
default_value: None,
auto_grow: true,
max_load_factor: 0.75,
_phantom: PhantomData,
}
}
pub fn with_capacity(mut self, capacity: usize) -> Self {
self.capacity = capacity.max(16);
self
}
pub fn with_default(mut self, default: V) -> Self {
self.default_value = Some(default);
self
}
pub fn auto_grow(mut self, enabled: bool) -> Self {
self.auto_grow = enabled;
self
}
pub fn max_load_factor(mut self, factor: f64) -> Self {
self.max_load_factor = factor.clamp(0.1, 0.95);
self
}
pub fn build(self) -> EasyHashMap<K, V> {
EasyHashMap {
inner: ZiporaHashMap::with_capacity(self.capacity)
.or_else(|_| ZiporaHashMap::with_capacity(self.capacity / 2))
.unwrap_or_default(),
default_value: self.default_value,
auto_grow: self.auto_grow,
max_load_factor: self.max_load_factor,
}
}
}
pub struct ValuesIterMut<'a, K, V>
where
K: Hash + Eq + Clone,
V: Clone,
{
keys: Vec<K>,
map: &'a EasyHashMap<K, V>,
current: usize,
}
impl<'a, K, V> Iterator for ValuesIterMut<'a, K, V>
where
K: Hash + Eq + Clone,
V: Clone,
{
type Item = V;
fn next(&mut self) -> Option<Self::Item> {
while self.current < self.keys.len() {
let key = &self.keys[self.current];
self.current += 1;
if let Some(value) = self.map.inner.get(key) {
return Some(value.clone());
}
}
None
}
}
#[derive(Debug, Clone)]
pub struct EasyHashMapStats {
pub len: usize,
pub capacity: usize,
pub load_factor: f64,
pub has_default: bool,
pub auto_grow_enabled: bool,
pub max_load_factor: f64,
}
impl<K, V> Default for EasyHashMap<K, V>
where
K: Hash + Eq + Clone,
V: Clone,
{
fn default() -> Self {
Self::new()
}
}
impl<K, V> Default for EasyHashMapBuilder<K, V>
where
K: Hash + Eq + Clone,
V: Clone,
{
fn default() -> Self {
Self::new()
}
}
impl<K, V> std::iter::FromIterator<(K, V)> for EasyHashMap<K, V>
where
K: Hash + Eq + Clone,
V: Clone,
{
fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
let mut map = Self::new();
map.extend(iter);
map
}
}
impl<K, V> std::iter::Extend<(K, V)> for EasyHashMap<K, V>
where
K: Hash + Eq + Clone,
V: Clone,
{
fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) {
self.extend(iter);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_basic_operations() {
let mut map = EasyHashMap::new();
map.put("key1", 42);
map.put("key2", 43);
assert_eq!(map.len(), 2);
assert_eq!(map.get(&"key1"), Some(&42));
assert_eq!(map.get(&"key2"), Some(&43));
assert_eq!(map.get(&"key3"), None);
assert!(map.contains_key(&"key1"));
assert!(!map.contains_key(&"key3"));
map.put("key1", 44);
assert_eq!(map.get(&"key1"), Some(&44));
assert_eq!(map.remove(&"key1"), Some(44));
assert_eq!(map.get(&"key1"), None);
assert_eq!(map.len(), 1);
}
#[test]
fn test_default_value() {
let mut map = EasyHashMap::with_default(0);
assert_eq!(map.get_or_default(&"missing"), &0);
map.put("real", 42);
assert_eq!(map.get_or_default(&"real"), &42);
assert_eq!(map.get_or_default(&"still_missing"), &0);
}
#[test]
fn test_get_or_insert() {
let mut map = EasyHashMap::new();
let value = map.get_or_insert("key1", 42).unwrap();
assert_eq!(*value, 42);
assert_eq!(map.len(), 1);
let value = map.get_or_insert("key1", 99).unwrap();
assert_eq!(*value, 42);
*value = 100;
assert_eq!(map.get(&"key1"), Some(&100));
}
#[test]
fn test_get_or_insert_with() {
let mut map = EasyHashMap::new();
let mut call_count = 0;
let value = map
.get_or_insert_with("key1", || {
call_count += 1;
42
})
.unwrap();
assert_eq!(*value, 42);
assert_eq!(call_count, 1);
let value = map
.get_or_insert_with("key1", || {
call_count += 1;
99
})
.unwrap();
assert_eq!(*value, 42); assert_eq!(call_count, 1); }
#[test]
fn test_extend() {
let mut map = EasyHashMap::new();
let data = vec![("a", 1), ("b", 2), ("c", 3)];
map.extend(data);
assert_eq!(map.len(), 3);
assert_eq!(map.get(&"a"), Some(&1));
assert_eq!(map.get(&"b"), Some(&2));
assert_eq!(map.get(&"c"), Some(&3));
}
#[test]
fn test_retain() {
let mut map = EasyHashMap::new();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
map.put("d", 4);
map.retain(|_k, v| *v % 2 == 0);
assert_eq!(map.len(), 2);
assert_eq!(map.get(&"b"), Some(&2));
assert_eq!(map.get(&"d"), Some(&4));
assert_eq!(map.get(&"a"), None);
assert_eq!(map.get(&"c"), None);
}
#[test]
fn test_builder_pattern() {
let map = EasyHashMap::<String, String>::initial_capacity(100)
.with_default(String::new())
.auto_grow(false)
.max_load_factor(0.5)
.build();
let stats = map.statistics();
assert!(stats.capacity >= 100);
assert!(stats.has_default);
assert!(!stats.auto_grow_enabled);
assert_eq!(stats.max_load_factor, 0.5);
}
#[test]
fn test_from_iterator() {
let data = vec![("x", 10), ("y", 20), ("z", 30)];
let map: EasyHashMap<&str, i32> = data.into_iter().collect();
assert_eq!(map.len(), 3);
assert_eq!(map.get(&"x"), Some(&10));
assert_eq!(map.get(&"y"), Some(&20));
assert_eq!(map.get(&"z"), Some(&30));
}
#[test]
fn test_iterators() {
let mut map = EasyHashMap::new();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
assert_eq!(map.get(&"a"), Some(&1));
assert_eq!(map.get(&"b"), Some(&2));
assert_eq!(map.get(&"c"), Some(&3));
}
#[test]
fn test_auto_growth() {
let mut map = EasyHashMap::initial_capacity(4)
.max_load_factor(0.5) .build();
let initial_capacity = map.capacity();
for i in 0..10 {
map.put(i, i * 2);
}
assert!(map.capacity() > initial_capacity);
assert_eq!(map.len(), 10);
for i in 0..10 {
assert_eq!(map.get(&i), Some(&(i * 2)));
}
}
#[test]
fn test_clear_and_shrink() {
let mut map = EasyHashMap::<i32, i32>::initial_capacity(1000).build();
for i in 0..10 {
map.put(i, i);
}
assert_eq!(map.len(), 10);
assert!(map.capacity() >= 1000);
map.clear();
assert_eq!(map.len(), 0);
assert!(map.capacity() >= 1000);
map.shrink_to_fit();
assert!(map.capacity() < 1000); }
#[test]
fn test_statistics() {
let map = EasyHashMap::<i32, i32>::with_default_value(42)
.auto_grow(false)
.max_load_factor(0.8)
.build();
let stats = map.statistics();
assert_eq!(stats.len, 0);
assert!(stats.capacity > 0);
assert_eq!(stats.load_factor, 0.0);
assert!(stats.has_default);
assert!(!stats.auto_grow_enabled);
assert_eq!(stats.max_load_factor, 0.8);
}
#[test]
fn test_large_scale() {
let mut map = EasyHashMap::new();
for i in 0..10000 {
map.put(i, i * 2);
}
assert_eq!(map.len(), 10000);
for i in (0..10000).step_by(100) {
assert_eq!(map.get(&i), Some(&(i * 2)));
}
for i in 0..5000 {
map.remove(&i);
}
assert_eq!(map.len(), 5000);
for i in 5000..10000 {
assert_eq!(map.get(&i), Some(&(i * 2)));
}
}
#[test]
fn test_error_resilience() {
let mut map = EasyHashMap::new();
map.put("key", 42);
map.put("key", 43);
assert_eq!(map.get(&"key"), Some(&43));
map.reserve(usize::MAX);
assert_eq!(map.get(&"key"), Some(&43));
}
}