oxihuman_core/
hash_bucket.rs1#![allow(dead_code)]
4
5#[derive(Debug, Clone)]
9#[allow(dead_code)]
10pub struct BucketEntry {
11 pub key: u64,
12 pub value: u64,
13}
14
15#[derive(Debug)]
17#[allow(dead_code)]
18pub struct HashBucket {
19 buckets: Vec<Vec<BucketEntry>>,
20 count: usize,
21}
22
23#[allow(dead_code)]
25pub fn new_hash_bucket(n_buckets: usize) -> HashBucket {
26 let n = if n_buckets == 0 { 16 } else { n_buckets };
27 HashBucket {
28 buckets: vec![Vec::new(); n],
29 count: 0,
30 }
31}
32
33fn bucket_idx(hb: &HashBucket, key: u64) -> usize {
34 (key as usize) % hb.buckets.len()
35}
36
37#[allow(dead_code)]
39pub fn hb_insert(hb: &mut HashBucket, key: u64, value: u64) {
40 let idx = bucket_idx(hb, key);
41 for entry in &mut hb.buckets[idx] {
42 if entry.key == key {
43 entry.value = value;
44 return;
45 }
46 }
47 hb.buckets[idx].push(BucketEntry { key, value });
48 hb.count += 1;
49}
50
51#[allow(dead_code)]
53pub fn hb_get(hb: &HashBucket, key: u64) -> Option<u64> {
54 let idx = bucket_idx(hb, key);
55 hb.buckets[idx]
56 .iter()
57 .find(|e| e.key == key)
58 .map(|e| e.value)
59}
60
61#[allow(dead_code)]
63pub fn hb_remove(hb: &mut HashBucket, key: u64) -> Option<u64> {
64 let idx = bucket_idx(hb, key);
65 let bucket = &mut hb.buckets[idx];
66 if let Some(pos) = bucket.iter().position(|e| e.key == key) {
67 let val = bucket.remove(pos).value;
68 hb.count -= 1;
69 Some(val)
70 } else {
71 None
72 }
73}
74
75#[allow(dead_code)]
77pub fn hb_contains(hb: &HashBucket, key: u64) -> bool {
78 hb_get(hb, key).is_some()
79}
80
81#[allow(dead_code)]
83pub fn hb_count(hb: &HashBucket) -> usize {
84 hb.count
85}
86
87#[allow(dead_code)]
89pub fn hb_bucket_count(hb: &HashBucket) -> usize {
90 hb.buckets.len()
91}
92
93#[allow(dead_code)]
95pub fn hb_clear(hb: &mut HashBucket) {
96 for bucket in &mut hb.buckets {
97 bucket.clear();
98 }
99 hb.count = 0;
100}
101
102#[allow(dead_code)]
104pub fn hb_keys(hb: &HashBucket) -> Vec<u64> {
105 hb.buckets
106 .iter()
107 .flat_map(|b| b.iter().map(|e| e.key))
108 .collect()
109}
110
111#[allow(dead_code)]
113pub fn hb_load_factor(hb: &HashBucket) -> f32 {
114 hb.count as f32 / hb.buckets.len() as f32
115}
116
117#[cfg(test)]
118mod tests {
119 use super::*;
120
121 #[test]
122 fn test_insert_get() {
123 let mut hb = new_hash_bucket(8);
124 hb_insert(&mut hb, 1, 100);
125 assert_eq!(hb_get(&hb, 1), Some(100));
126 }
127
128 #[test]
129 fn test_update() {
130 let mut hb = new_hash_bucket(8);
131 hb_insert(&mut hb, 5, 10);
132 hb_insert(&mut hb, 5, 20);
133 assert_eq!(hb_get(&hb, 5), Some(20));
134 assert_eq!(hb_count(&hb), 1);
135 }
136
137 #[test]
138 fn test_remove() {
139 let mut hb = new_hash_bucket(8);
140 hb_insert(&mut hb, 3, 300);
141 assert_eq!(hb_remove(&mut hb, 3), Some(300));
142 assert!(!hb_contains(&hb, 3));
143 }
144
145 #[test]
146 fn test_contains() {
147 let mut hb = new_hash_bucket(8);
148 hb_insert(&mut hb, 7, 77);
149 assert!(hb_contains(&hb, 7));
150 assert!(!hb_contains(&hb, 8));
151 }
152
153 #[test]
154 fn test_count() {
155 let mut hb = new_hash_bucket(4);
156 hb_insert(&mut hb, 1, 1);
157 hb_insert(&mut hb, 2, 2);
158 assert_eq!(hb_count(&hb), 2);
159 }
160
161 #[test]
162 fn test_clear() {
163 let mut hb = new_hash_bucket(8);
164 hb_insert(&mut hb, 1, 1);
165 hb_clear(&mut hb);
166 assert_eq!(hb_count(&hb), 0);
167 }
168
169 #[test]
170 fn test_keys() {
171 let mut hb = new_hash_bucket(8);
172 hb_insert(&mut hb, 10, 1);
173 hb_insert(&mut hb, 20, 2);
174 let mut keys = hb_keys(&hb);
175 keys.sort();
176 assert_eq!(keys, vec![10, 20]);
177 }
178
179 #[test]
180 fn test_collision_same_bucket() {
181 let mut hb = new_hash_bucket(1);
182 hb_insert(&mut hb, 1, 111);
183 hb_insert(&mut hb, 2, 222);
184 assert_eq!(hb_get(&hb, 1), Some(111));
185 assert_eq!(hb_get(&hb, 2), Some(222));
186 }
187
188 #[test]
189 fn test_load_factor() {
190 let mut hb = new_hash_bucket(10);
191 hb_insert(&mut hb, 1, 1);
192 hb_insert(&mut hb, 2, 2);
193 let lf = hb_load_factor(&hb);
194 assert!((lf - 0.2_f32).abs() < 1e-5);
195 }
196}