use core::hash::Hash;
use super::SetTrait;
use crate::containers::probing::{find_key_with_hash, ProbableSlot};
#[derive(Debug)]
enum Slot<K> {
Occupied(K), Empty, Tombstone, }
#[derive(Debug)]
pub struct Set<K, const N: usize> {
slots: [Slot<K>; N], }
impl<K: Eq> ProbableSlot<K> for Slot<K> {
fn contains_key(&self, key: &K) -> bool {
match self {
Slot::Occupied(stored_key) => stored_key == key,
_ => false,
}
}
fn is_empty(&self) -> bool {
matches!(self, Slot::Empty)
}
fn is_tombstone(&self) -> bool {
matches!(self, Slot::Tombstone)
}
}
impl<K: Eq + Hash, const N: usize> Set<K, N> {
fn find_key_with_hash(&self, key: &K) -> (bool, usize) {
find_key_with_hash(&self.slots, key)
}
}
impl<K: Eq + Hash, const N: usize> Default for Set<K, N> {
fn default() -> Self {
Self::new()
}
}
impl<K: Eq + Hash, const N: usize> SetTrait<K> for Set<K, N> {
fn new() -> Self
where
Self: Sized,
{
Self {
slots: core::array::from_fn(|_| Slot::Empty), }
}
fn insert(&mut self, key: K) -> Result<bool, K> {
if N == 0 {
return Err(key);
}
let (exists, index) = self.find_key_with_hash(&key);
if !exists {
match &self.slots[index] {
Slot::Empty | Slot::Tombstone => {
self.slots[index] = Slot::Occupied(key);
Ok(true)
}
Slot::Occupied(_) => {
Err(key)
}
}
} else {
Ok(false) }
}
fn remove(&mut self, key: &K) -> bool {
let (exists, index) = self.find_key_with_hash(key);
if exists {
self.slots[index] = Slot::Tombstone; }
exists
}
fn contains(&self, key: &K) -> bool {
self.find_key_with_hash(key).0
}
fn len(&self) -> usize {
self.slots
.iter()
.filter(|s| matches!(s, Slot::Occupied(_)))
.count()
}
fn is_empty(&self) -> bool {
self.len() == 0
}
fn clear(&mut self) {
self.slots = core::array::from_fn(|_| Slot::Empty);
}
}
#[cfg(test)]
mod collision_behavior_tests {
use super::*;
#[test]
fn test_basic_operations_in_small_table() {
let mut set: Set<i32, 10> = Set::new();
assert!(set.insert(0).unwrap());
assert!(set.insert(10).unwrap());
assert!(set.insert(20).unwrap());
assert_eq!(set.len(), 3);
assert!(set.contains(&0));
assert!(set.contains(&10));
assert!(set.contains(&20));
}
#[test]
fn test_forced_collisions_in_small_table() {
let mut set: Set<i32, 2> = Set::new();
assert!(set.insert(1).unwrap());
assert!(set.insert(2).unwrap());
assert!(set.remove(&1));
assert!(set.insert(3).unwrap());
assert_eq!(set.len(), 2);
assert!(!set.contains(&1)); assert!(set.contains(&2));
assert!(set.contains(&3));
}
#[test]
fn test_lookup_with_potential_collisions() {
let mut set: Set<i32, 2> = Set::new();
set.insert(1).unwrap();
set.insert(2).unwrap();
assert!(set.contains(&1));
assert!(set.contains(&2));
assert!(!set.contains(&3));
}
#[test]
fn test_tombstone_handling() {
let mut set: Set<i32, 2> = Set::new();
set.insert(1).unwrap();
set.insert(2).unwrap();
assert!(set.remove(&1));
assert_eq!(set.len(), 1);
assert!(set.insert(3).unwrap());
assert_eq!(set.len(), 2);
assert!(!set.contains(&1)); assert!(set.contains(&2)); assert!(set.contains(&3)); }
#[test]
fn test_duplicate_insertion_behavior() {
let mut set: Set<i32, 3> = Set::new();
set.insert(1).unwrap();
set.insert(2).unwrap();
assert!(!set.insert(2).unwrap());
assert_eq!(set.len(), 2); assert!(set.contains(&1));
assert!(set.contains(&2));
}
#[test]
fn test_clear_functionality() {
let mut set: Set<i32, 3> = Set::new();
set.insert(0).unwrap();
set.insert(3).unwrap();
set.insert(6).unwrap();
assert_eq!(set.len(), 3);
set.clear();
assert_eq!(set.len(), 0);
assert!(set.is_empty());
assert!(set.insert(1).unwrap());
assert_eq!(set.len(), 1);
assert!(set.contains(&1));
}
#[test]
fn test_operations_with_potential_collisions() {
let mut set: Set<i32, 5> = Set::new();
for i in 0..5 {
let value = i * 5; set.insert(value).unwrap();
}
assert_eq!(set.len(), 5);
for i in 0..5 {
let value = i * 5;
assert!(set.contains(&value));
}
assert!(set.remove(&10));
assert_eq!(set.len(), 4);
assert!(!set.contains(&10));
assert!(set.contains(&0));
assert!(set.contains(&5));
assert!(set.contains(&15));
assert!(set.contains(&20));
}
#[test]
fn test_string_keys_in_small_table() {
let mut set: Set<&'static str, 3> = Set::new();
let keys = ["a", "b", "c", "d"];
let mut successful_inserts = 0;
for &key in &keys {
if set.insert(key).is_ok() {
successful_inserts += 1;
}
}
assert_eq!(successful_inserts, 3);
assert_eq!(set.len(), 3);
let mut found_count = 0;
for &key in &keys {
if set.contains(&key) {
found_count += 1;
}
}
assert_eq!(found_count, 3);
}
#[test]
fn test_full_table_operations() {
let mut set: Set<i32, 2> = Set::new();
assert!(set.insert(1).unwrap());
assert!(set.insert(2).unwrap());
assert!(set.remove(&1)); assert!(set.insert(3).unwrap());
assert_eq!(set.len(), 2);
assert!(!set.contains(&1));
assert!(set.contains(&2));
assert!(set.contains(&3));
}
#[test]
fn test_default_constructor() {
let set: Set<i32, 10> = Set::default();
assert!(set.is_empty());
assert_eq!(set.len(), 0);
}
#[test]
fn test_remove_patterns_with_collisions() {
let mut set: Set<i32, 4> = Set::new();
set.insert(0).unwrap(); set.insert(4).unwrap(); set.insert(8).unwrap();
assert!(set.remove(&4));
assert!(set.insert(12).unwrap());
assert_eq!(set.len(), 3);
assert!(set.contains(&0));
assert!(!set.contains(&4)); assert!(set.contains(&8));
assert!(set.contains(&12));
}
#[test]
fn test_zero_capacity_insert() {
let mut set: Set<i32, 0> = Set::new();
assert!(set.is_empty());
assert_eq!(set.insert(1), Err(1));
assert!(set.is_empty());
}
}