use core::*;
use crate::mem::*;
use crate::hash::*;
struct KeyValue<K : Hash + PartialEq, V> {
hash : usize,
key : K,
value : V,
}
impl<K: Hash + PartialEq, V> KeyValue<K, V> {
pub fn isEmpty(&self) -> bool { self.hash == 0 }
}
pub struct HashMap<K: Hash + PartialEq, V> {
table : Unique<KeyValue<K, V>>,
capacity: usize,
count : usize,
}
impl<K: Hash + PartialEq, V> HashMap<K, V> {
pub fn new() -> Self {
Self {
table : Unique::new(ptr::null_mut()),
count : 0,
capacity: 0,
}
}
pub fn count(&self) -> usize { self.count }
#[inline]
fn hash(k: &K) -> usize {
match k.hash() {
0 => 1,
h => h,
}
}
#[inline]
fn next(&self, index: isize) -> isize {
let mut ret = index - 1;
if ret < 0 { ret += self.capacity as isize }
ret
}
fn uncheckedSet(&mut self, k: K, v: V) {
let hash = Self::hash(&k);
let mut index = (hash & (self.capacity - 1)) as isize;
let entries = unsafe { core::slice::from_raw_parts_mut(self.table.getMutPtr(), self.capacity) };
for _ in 0..self.capacity {
let mut e = &mut entries[index as usize];
if e.isEmpty() {
e.key = k;
e.value = v;
e.hash = hash;
self.count += 1;
return;
}
if hash == e.hash && k == e.key {
e.value = v;
return;
}
index = self.next(index);
}
panic!("uncheckedSet shouldn't reach this point");
}
fn newWithCap(cap: usize) -> Self {
Self {
table : Unique::new(unsafe { allocRaw(cap * ::core::mem::size_of::<KeyValue<K, V>>()) as *mut KeyValue<K, V> }),
count : 0,
capacity: cap,
}
}
fn grow(&mut self, newCap: usize) {
let oldEntries = unsafe { core::slice::from_raw_parts(self.table.getPtr(), self.capacity) };
let mut newHM = HashMap::<K, V>::newWithCap(newCap);
for o in oldEntries {
if !o.isEmpty() {
unsafe {
newHM.uncheckedSet(::core::ptr::read_unaligned(&o.key),
::core::ptr::read_unaligned(&o.value));
}
}
}
self.count = 0;
self.capacity = 0;
unsafe { free(self.table.getMutPtr()) };
*self = newHM;
}
pub fn set(&mut self, k: K, v: V) {
if 4 * self.count >= 3 * self.capacity {
self.grow(if self.capacity == 0 { 4 } else { self.capacity * 2 });
}
self.uncheckedSet(k, v)
}
pub fn exist(&self, k: K) -> bool {
let hash = Self::hash(&k);
let mut index = (hash & (self.capacity - 1)) as isize;
let entries = unsafe { core::slice::from_raw_parts(self.table.getPtr(), self.capacity) };
for _ in 0..self.capacity {
let e = &entries[index as usize];
if e.isEmpty() {
return false;
}
if hash == e.hash && k == e.key {
return true;
}
index = self.next(index);
}
false
}
pub fn get(&self, k: K) -> Option<&V> {
let hash = Self::hash(&k);
let mut index = (hash & (self.capacity - 1)) as isize;
let entries = unsafe { core::slice::from_raw_parts(self.table.getPtr(), self.capacity) };
for _ in 0..self.capacity {
let e = &entries[index as usize];
if e.isEmpty() {
return None;
}
if hash == e.hash && k == e.key {
return Some(&e.value);
}
index = self.next(index);
}
None
}
pub fn remove(&mut self, k: K) {
let hash = Self::hash(&k);
let mut index = (hash & (self.capacity - 1)) as isize;
let entries = unsafe { core::slice::from_raw_parts_mut(self.table.getMutPtr(), self.capacity) };
for _ in 0..self.capacity {
let e = &entries[index as usize];
if e.isEmpty() {
return;
}
if hash == e.hash && k == e.key {
self.count -= 1;
break;
}
index = self.next(index);
}
loop {
let emptyIndex = index;
let mut originalIndex;
loop {
index = self.next(index);
let s = &entries[index as usize];
if s.isEmpty() {
entries[emptyIndex as usize].hash = 0;
unsafe { ::core::ptr::read_unaligned(&entries[emptyIndex as usize]) }; return;
}
originalIndex = (s.hash & (self.capacity - 1)) as isize;
if ! ((index <= originalIndex && originalIndex < emptyIndex)
|| (originalIndex < emptyIndex && emptyIndex < index)
|| (emptyIndex < index && index <= originalIndex)) {
break;
}
}
entries[emptyIndex as usize] = unsafe { ::core::ptr::read_unaligned(&entries[index as usize]) };
entries[index as usize].hash = 0;
}
}
}
impl<K : Hash + PartialEq, V> Drop for HashMap<K, V> {
fn drop(&mut self) {
if self.capacity > 0 {
let arr = unsafe { core::slice::from_raw_parts_mut(self.table.getMutPtr(), self.capacity) };
for kv in arr {
if !kv.isEmpty() {
unsafe { ptr::drop_in_place(&kv.key as *const K as *mut K) };
unsafe { ptr::drop_in_place(&kv.value as *const V as *mut V) };
}
}
unsafe { free(self.table.getMutPtr()) }
}
}
}
impl Hash for i32 {
fn hash(&self) -> usize { *self as usize }
}
#[cfg(test)]
mod test {
use super::*;
use crate::vec::*;
#[test]
fn testInsert() {
let mut hm = HashMap::<i32, i32>::new();
for i in 0..100 {
hm.set(i, i * 2);
}
for i in 0..100 {
let ret = hm.get(i);
assert!(ret.is_some());
match ret {
Some(o) => assert!(*o == i * 2),
None => assert!(false)
}
}
}
#[test]
fn testRemove() {
let mut hm = HashMap::<i32, i32>::new();
for i in 0..100 {
hm.set(i, i * 2);
}
for i in 45..55 {
hm.remove(i);
assert!(hm.exist(i) == false);
}
for i in 0..45 {
let ret = hm.get(i);
assert!(ret.is_some());
match ret {
Some(o) => assert!(*o == i * 2),
None => assert!(false)
}
}
for i in 55..100 {
let ret = hm.get(i);
assert!(ret.is_some());
match ret {
Some(o) => assert!(*o == i * 2),
None => assert!(false)
}
}
for i in 45..55 {
assert!(hm.exist(i) == false);
}
assert!(hm.count() == 90);
}
#[test]
fn testVecInsert() {
let mut hm = HashMap::<i32, Vec<i32>>::new();
for i in 0..100 {
let mut v = Vec::new();
for j in 0..i * 2 {
v.pushBack(j);
}
hm.set(i, v);
}
for i in 0..100 {
let ret = hm.get(i);
assert!(ret.is_some());
match ret {
Some(o) => {
for j in 0..i*2 {
assert!((*o)[j as usize] == j)
}
}
None => assert!(false)
}
}
}
#[test]
fn testVecRemove() {
let mut hm = HashMap::<i32, Vec<i32>>::new();
for i in 0..100 {
let mut v = Vec::new();
for j in 0..i * 2 {
v.pushBack(j);
}
hm.set(i, v);
}
for i in 45..55 {
hm.remove(i);
assert!(hm.exist(i) == false);
}
for i in 0..45 {
let ret = hm.get(i);
assert!(ret.is_some());
match ret {
Some(o) => {
for j in 0..i*2 {
assert!((*o)[j as usize] == j)
}
},
None => assert!(false)
}
}
for i in 55..100 {
let ret = hm.get(i);
assert!(ret.is_some());
match ret {
Some(o) => {
for j in 0..i*2 {
assert!((*o)[j as usize] == j)
}
},
None => assert!(false)
}
}
for i in 45..55 {
assert!(hm.exist(i) == false);
}
assert!(hm.count() == 90);
}
}