1use crate::Value;
2use crate::arena::{Arena, Index};
3
4const CHUNK_SIZE: usize = 8; const DEFAULT_CAPACITY: usize = 16;
6const LOAD_FACTOR_THRESHOLD: f64 = 0.75;
7
8pub type HashMapHandle = Index;
9
10#[derive(Debug, Clone)]
11pub struct HashMapObject {
12 pub first_chunk: Option<BucketChunkHandle>,
13 pub len: usize,
14 pub capacity: usize,
15 pub is_marked: bool,
16}
17
18impl HashMapObject {
19 pub fn new(capacity: usize) -> Self {
20 Self {
21 first_chunk: None,
22 len: 0,
23 capacity,
24 is_marked: false,
25 }
26 }
27}
28
29#[derive(Debug, Clone)]
30pub struct BucketChunk {
31 pub buckets: [Bucket; CHUNK_SIZE],
32 pub next_chunk: Option<BucketChunkHandle>,
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Default)]
36pub struct BucketChunkHandle(Index);
37
38#[derive(Debug, Clone, Copy)]
39pub struct Bucket {
40 pub kind: BucketKind,
41}
42
43#[derive(Debug, Clone, Copy)]
44pub enum BucketKind {
45 Empty,
46 Occupied { key: Value, value: Value },
47 Tombstone,
48}
49
50impl Default for Bucket {
51 fn default() -> Self {
52 Bucket {
53 kind: BucketKind::Empty,
54 }
55 }
56}
57
58impl Default for BucketChunk {
59 fn default() -> Self {
60 BucketChunk {
61 buckets: [Bucket::default(); CHUNK_SIZE],
62 next_chunk: None,
63 }
64 }
65}
66
67#[derive(Debug, Default, Clone)]
68pub struct HashMapArena {
69 hashmaps: Arena<HashMapObject>,
70 chunks: Arena<BucketChunk>,
71}
72
73impl HashMapArena {
74 pub fn new() -> Self {
75 Self::with_capacity(64)
76 }
77
78 pub fn with_capacity(initial_capacity: usize) -> Self {
79 Self {
80 hashmaps: Arena::with_capacity(initial_capacity),
81 chunks: Arena::with_capacity(initial_capacity * 4),
82 }
83 }
84
85 pub fn new_hashmap(&mut self) -> HashMapHandle {
86 self.new_hashmap_with_capacity(DEFAULT_CAPACITY)
87 }
88
89 pub fn new_hashmap_with_capacity(&mut self, capacity: usize) -> HashMapHandle {
90 let hashmap = HashMapObject::new(capacity);
91 self.hashmaps.insert(hashmap)
92 }
93
94 pub fn insert(&mut self, handle: HashMapHandle, key: Value, value: Value) -> Option<Value> {
95 let hash = key.hash();
96
97 if let Some(hashmap) = self.hashmaps.get(handle) {
99 let load_factor = hashmap.len as f64 / hashmap.capacity as f64;
100 if load_factor >= LOAD_FACTOR_THRESHOLD {
101 self.resize_hashmap(handle);
102 }
103 }
104
105 self.insert_with_hash(handle, key, value, hash)
106 }
107
108 fn insert_with_hash(
109 &mut self,
110 handle: HashMapHandle,
111 key: Value,
112 value: Value,
113 hash: u64,
114 ) -> Option<Value> {
115 let capacity = self.hashmaps.get(handle)?.capacity;
116 let bucket_index = (hash as usize) % capacity;
117
118 let (chunk_handle, bucket_idx_in_chunk) = self.ensure_bucket_exists(handle, bucket_index);
120
121 let mut current_chunk = chunk_handle;
123 let mut current_bucket_idx = bucket_idx_in_chunk;
124 let mut probed = 0;
125
126 loop {
127 if let Some(chunk) = self.chunks.get_mut(current_chunk.0) {
128 let bucket = &mut chunk.buckets[current_bucket_idx];
129
130 match bucket.kind {
131 BucketKind::Empty | BucketKind::Tombstone => {
132 bucket.kind = BucketKind::Occupied { key, value };
134 if let Some(hashmap) = self.hashmaps.get_mut(handle) {
135 hashmap.len += 1;
136 }
137 return None;
138 }
139 BucketKind::Occupied {
140 key: existing_key,
141 value: existing_value,
142 } => {
143 if existing_key == key {
144 bucket.kind = BucketKind::Occupied { key, value };
146 return Some(existing_value);
147 }
148 }
150 }
151 }
152
153 current_bucket_idx += 1;
155 if current_bucket_idx >= CHUNK_SIZE {
156 current_bucket_idx = 0;
157 if let Some(chunk) = self.chunks.get(current_chunk.0) {
158 if let Some(next_chunk) = chunk.next_chunk {
159 current_chunk = next_chunk;
160 } else {
161 let new_chunk = BucketChunk::default();
163 let new_chunk_handle = BucketChunkHandle(self.chunks.insert(new_chunk));
164
165 if let Some(chunk) = self.chunks.get_mut(current_chunk.0) {
167 chunk.next_chunk = Some(new_chunk_handle);
168 }
169 current_chunk = new_chunk_handle;
170 }
171 }
172 }
173
174 probed += 1;
175 if probed >= capacity {
176 break;
178 }
179 }
180
181 None
182 }
183
184 pub fn get(&self, handle: HashMapHandle, key: &Value) -> Option<Value> {
185 let hashmap = self.hashmaps.get(handle)?;
186 let hash = key.hash();
187 let bucket_index = (hash as usize) % hashmap.capacity;
188
189 let (chunk_handle, bucket_idx_in_chunk) = self.get_bucket_position(handle, bucket_index)?;
190
191 let mut current_chunk = chunk_handle;
193 let mut current_bucket_idx = bucket_idx_in_chunk;
194 let mut probed = 0;
195
196 loop {
197 if let Some(chunk) = self.chunks.get(current_chunk.0) {
198 let bucket = &chunk.buckets[current_bucket_idx];
199
200 match bucket.kind {
201 BucketKind::Empty => {
202 return None;
204 }
205 BucketKind::Occupied {
206 key: existing_key,
207 value,
208 } => {
209 if existing_key == *key {
210 return Some(value);
211 }
212 }
213 BucketKind::Tombstone => {
214 }
216 }
217 }
218
219 current_bucket_idx += 1;
221 if current_bucket_idx >= CHUNK_SIZE {
222 current_bucket_idx = 0;
223 if let Some(chunk) = self.chunks.get(current_chunk.0) {
224 if let Some(next_chunk) = chunk.next_chunk {
225 current_chunk = next_chunk;
226 } else {
227 break;
228 }
229 }
230 }
231
232 probed += 1;
233 if probed >= hashmap.capacity {
234 break;
235 }
236 }
237
238 None
239 }
240
241 pub fn remove(&mut self, handle: HashMapHandle, key: &Value) -> Option<Value> {
242 let hashmap = self.hashmaps.get(handle)?;
243 let hash = key.hash();
244 let bucket_index = (hash as usize) % hashmap.capacity;
245
246 let (chunk_handle, bucket_idx_in_chunk) = self.get_bucket_position(handle, bucket_index)?;
247
248 let mut current_chunk = chunk_handle;
250 let mut current_bucket_idx = bucket_idx_in_chunk;
251 let mut probed = 0;
252
253 loop {
254 if let Some(chunk) = self.chunks.get_mut(current_chunk.0) {
255 let bucket = &mut chunk.buckets[current_bucket_idx];
256
257 match bucket.kind {
258 BucketKind::Empty => {
259 return None;
261 }
262 BucketKind::Occupied {
263 key: existing_key,
264 value,
265 } => {
266 if existing_key == *key {
267 bucket.kind = BucketKind::Tombstone;
268 if let Some(hashmap) = self.hashmaps.get_mut(handle) {
269 hashmap.len -= 1;
270 }
271 return Some(value);
272 }
273 }
274 BucketKind::Tombstone => {
275 }
277 }
278 }
279
280 current_bucket_idx += 1;
282 if current_bucket_idx >= CHUNK_SIZE {
283 current_bucket_idx = 0;
284 if let Some(chunk) = self.chunks.get(current_chunk.0) {
285 if let Some(next_chunk) = chunk.next_chunk {
286 current_chunk = next_chunk;
287 } else {
288 break;
289 }
290 }
291 }
292
293 probed += 1;
294 if probed >= hashmap.capacity {
295 break;
296 }
297 }
298
299 None
300 }
301
302 pub fn len(&self, handle: HashMapHandle) -> usize {
303 self.hashmaps.get(handle).map(|hm| hm.len).unwrap_or(0)
304 }
305
306 pub fn is_empty(&self, handle: HashMapHandle) -> bool {
307 self.len(handle) == 0
308 }
309
310 fn ensure_bucket_exists(
311 &mut self,
312 handle: HashMapHandle,
313 bucket_index: usize,
314 ) -> (BucketChunkHandle, usize) {
315 let hashmap = self.hashmaps.get_mut(handle).unwrap();
316
317 if hashmap.first_chunk.is_none() {
319 let chunk = BucketChunk::default();
320 let chunk_handle = BucketChunkHandle(self.chunks.insert(chunk));
321 hashmap.first_chunk = Some(chunk_handle);
322 }
323
324 let chunk_handle = hashmap.first_chunk.unwrap();
325 let bucket_idx_in_chunk = bucket_index % CHUNK_SIZE;
326
327 (chunk_handle, bucket_idx_in_chunk)
328 }
329
330 fn get_bucket_position(
331 &self,
332 handle: HashMapHandle,
333 bucket_index: usize,
334 ) -> Option<(BucketChunkHandle, usize)> {
335 let hashmap = self.hashmaps.get(handle)?;
336 let chunk_handle = hashmap.first_chunk?;
337 let bucket_idx_in_chunk = bucket_index % CHUNK_SIZE;
338
339 Some((chunk_handle, bucket_idx_in_chunk))
340 }
341
342 fn resize_hashmap(&mut self, handle: HashMapHandle) {
343 let old_capacity = self.hashmaps.get(handle).unwrap().capacity;
345 let new_capacity = old_capacity * 2;
346
347 let current_len = self.hashmaps.get(handle).map(|hm| hm.len).unwrap_or(0);
350 let mut pairs = Vec::with_capacity(current_len);
351 if let Some(hashmap) = self.hashmaps.get(handle)
352 && let Some(first_chunk) = hashmap.first_chunk
353 {
354 self.collect_all_pairs(first_chunk, &mut pairs);
355 }
356
357 if let Some(hashmap) = self.hashmaps.get_mut(handle) {
359 hashmap.first_chunk = None;
360 hashmap.len = 0;
361 hashmap.capacity = new_capacity;
362 }
363
364 for (key, value) in pairs {
366 let hash = key.hash();
367 self.insert_with_hash(handle, key, value, hash);
368 }
369 }
370
371 fn collect_all_pairs(&self, chunk_handle: BucketChunkHandle, pairs: &mut Vec<(Value, Value)>) {
372 if let Some(chunk) = self.chunks.get(chunk_handle.0) {
373 for bucket in &chunk.buckets {
374 if let BucketKind::Occupied { key, value } = bucket.kind {
375 pairs.push((key, value));
376 }
377 }
378
379 if let Some(next_chunk) = chunk.next_chunk {
380 self.collect_all_pairs(next_chunk, pairs);
381 }
382 }
383 }
384
385 pub fn iter(&self, handle: HashMapHandle) -> HashMapIterator<'_> {
386 HashMapIterator::new(self, handle)
387 }
388
389 pub fn mark_hashmap(&mut self, handle: HashMapHandle) {
390 if let Some(hashmap) = self.hashmaps.get_mut(handle) {
391 hashmap.is_marked = true;
392 }
393 }
394
395 pub fn copy_into(&mut self, source_handle: HashMapHandle, destination_handle: HashMapHandle) {
396 if source_handle == destination_handle {
397 return;
398 }
399
400 let source_first_chunk = match self.hashmaps.get(source_handle) {
401 Some(hashmap) => hashmap.first_chunk,
402 None => return,
403 };
404
405 if self.hashmaps.get(destination_handle).is_none() {
406 return;
407 }
408
409 if let Some(first_chunk) = source_first_chunk {
410 self.copy_all_pairs_from_chunk(first_chunk, destination_handle);
411 }
412 }
413
414 fn copy_all_pairs_from_chunk(
415 &mut self,
416 chunk_handle: BucketChunkHandle,
417 destination_handle: HashMapHandle,
418 ) {
419 let chunk_data = if let Some(chunk) = self.chunks.get(chunk_handle.0) {
420 let mut pairs: [(Value, Value); CHUNK_SIZE] =
422 [(Value::nil(), Value::nil()); CHUNK_SIZE];
423 let mut count = 0;
424
425 for bucket in &chunk.buckets {
426 if let BucketKind::Occupied { key, value } = bucket.kind {
427 pairs[count] = (key, value);
428 count += 1;
429 }
430 }
431 let next_chunk = chunk.next_chunk;
432 (pairs, count, next_chunk)
433 } else {
434 return;
435 };
436
437 for i in 0..chunk_data.1 {
439 let (key, value) = chunk_data.0[i];
440 self.insert(destination_handle, key, value);
441 }
442
443 if let Some(next_chunk) = chunk_data.2 {
444 self.copy_all_pairs_from_chunk(next_chunk, destination_handle);
445 }
446 }
447
448 pub fn collect_garbage(&mut self) {
449 let estimated_deletions = (self.hashmaps.len() / 4).max(8);
450 let mut deleted_hashmaps = Vec::with_capacity(estimated_deletions);
451
452 for (handle, hashmap) in self.hashmaps.iter_mut() {
454 if hashmap.is_marked {
455 hashmap.is_marked = false; } else {
457 deleted_hashmaps.push(handle);
458 }
459 }
460
461 for handle in deleted_hashmaps {
462 self.delete_hashmap(handle);
463 }
464 }
465
466 pub fn delete_hashmap(&mut self, handle: HashMapHandle) -> bool {
467 if let Some(hashmap) = self.hashmaps.get(handle) {
468 if let Some(first_chunk) = hashmap.first_chunk {
469 self.mark_chunks_for_cleanup(first_chunk);
470 }
471
472 self.hashmaps.remove(handle);
473 true
474 } else {
475 false
476 }
477 }
478
479 fn mark_chunks_for_cleanup(&mut self, chunk_handle: BucketChunkHandle) {
480 if let Some(chunk) = self.chunks.get(chunk_handle.0) {
481 let next_chunk = chunk.next_chunk;
482 self.chunks.remove(chunk_handle.0);
483
484 if let Some(next) = next_chunk {
485 self.mark_chunks_for_cleanup(next);
486 }
487 }
488 }
489
490 pub fn get_allocated_bytes(&self) -> usize {
491 let hashmap_bytes = self.hashmaps.len() * std::mem::size_of::<HashMapObject>();
492 let chunk_bytes = self.chunks.len() * std::mem::size_of::<BucketChunk>();
493 hashmap_bytes + chunk_bytes
494 }
495}
496
497pub struct HashMapIterator<'a> {
498 arena: &'a HashMapArena,
499 current_chunk: Option<BucketChunkHandle>,
500 current_bucket_idx: usize,
501}
502
503impl<'a> HashMapIterator<'a> {
504 fn new(arena: &'a HashMapArena, handle: HashMapHandle) -> Self {
505 let current_chunk = arena.hashmaps.get(handle).and_then(|hm| hm.first_chunk);
506
507 Self {
508 arena,
509 current_chunk,
510 current_bucket_idx: 0,
511 }
512 }
513}
514
515impl<'a> Iterator for HashMapIterator<'a> {
516 type Item = (Value, Value);
517
518 fn next(&mut self) -> Option<Self::Item> {
519 while let Some(chunk_handle) = self.current_chunk {
520 if let Some(chunk) = self.arena.chunks.get(chunk_handle.0) {
521 while self.current_bucket_idx < CHUNK_SIZE {
523 let bucket = &chunk.buckets[self.current_bucket_idx];
524 self.current_bucket_idx += 1;
525
526 if let BucketKind::Occupied { key, value } = bucket.kind {
527 return Some((key, value));
528 }
529 }
530
531 self.current_chunk = chunk.next_chunk;
533 self.current_bucket_idx = 0;
534 } else {
535 break;
536 }
537 }
538
539 None
540 }
541}
542
543#[cfg(test)]
544mod tests {
545 use super::*;
546
547 fn create_test_value(n: i32) -> Value {
548 Value::number(n as f64)
549 }
550
551 #[test]
552 fn test_new_hashmap() {
553 let mut arena = HashMapArena::new();
554 let handle = arena.new_hashmap();
555
556 assert_eq!(arena.len(handle), 0);
557 assert!(arena.is_empty(handle));
558 }
559
560 #[test]
561 fn test_insert_and_get() {
562 let mut arena = HashMapArena::new();
563 let handle = arena.new_hashmap();
564
565 let key1 = create_test_value(1);
566 let value1 = create_test_value(100);
567
568 let old_value = arena.insert(handle, key1, value1);
570 assert!(old_value.is_none());
571 assert_eq!(arena.len(handle), 1);
572
573 let retrieved = arena.get(handle, &key1);
575 assert_eq!(retrieved, Some(value1));
576 }
577
578 #[test]
579 fn test_insert_duplicate_key() {
580 let mut arena = HashMapArena::new();
581 let handle = arena.new_hashmap();
582
583 let key = create_test_value(1);
584 let value1 = create_test_value(100);
585 let value2 = create_test_value(200);
586
587 arena.insert(handle, key, value1);
589 assert_eq!(arena.len(handle), 1);
590
591 let old_value = arena.insert(handle, key, value2);
593 assert_eq!(old_value, Some(value1));
594 assert_eq!(arena.len(handle), 1);
595
596 assert_eq!(arena.get(handle, &key), Some(value2));
598 }
599
600 #[test]
601 fn test_multiple_insertions() {
602 let mut arena = HashMapArena::new();
603 let handle = arena.new_hashmap();
604
605 for i in 0..10 {
606 let key = create_test_value(i);
607 let value = create_test_value(i * 10);
608 arena.insert(handle, key, value);
609 }
610
611 assert_eq!(arena.len(handle), 10);
612
613 for i in 0..10 {
615 let key = create_test_value(i);
616 let expected_value = create_test_value(i * 10);
617 assert_eq!(arena.get(handle, &key), Some(expected_value));
618 }
619 }
620
621 #[test]
622 fn test_remove() {
623 let mut arena = HashMapArena::new();
624 let handle = arena.new_hashmap();
625
626 let key = create_test_value(1);
627 let value = create_test_value(100);
628
629 arena.insert(handle, key, value);
631 assert_eq!(arena.len(handle), 1);
632
633 let removed_value = arena.remove(handle, &key);
634 assert_eq!(removed_value, Some(value));
635 assert_eq!(arena.len(handle), 0);
636 assert!(arena.is_empty(handle));
637
638 assert_eq!(arena.get(handle, &key), None);
640 }
641
642 #[test]
643 fn test_remove_nonexistent_key() {
644 let mut arena = HashMapArena::new();
645 let handle = arena.new_hashmap();
646
647 let key = create_test_value(1);
648 let removed = arena.remove(handle, &key);
649 assert!(removed.is_none());
650 assert_eq!(arena.len(handle), 0);
651 }
652
653 #[test]
654 fn test_get_nonexistent_key() {
655 let mut arena = HashMapArena::new();
656 let handle = arena.new_hashmap();
657
658 let key = create_test_value(1);
659 let result = arena.get(handle, &key);
660 assert!(result.is_none());
661 }
662
663 #[test]
664 fn test_linear_probing_collision() {
665 let mut arena = HashMapArena::new();
666 let handle = arena.new_hashmap_with_capacity(4); let key1 = create_test_value(1);
670 let key2 = create_test_value(2);
671 let key3 = create_test_value(3);
672 let value1 = create_test_value(100);
673 let value2 = create_test_value(200);
674 let value3 = create_test_value(300);
675
676 arena.insert(handle, key1, value1);
677 arena.insert(handle, key2, value2);
678 arena.insert(handle, key3, value3);
679
680 assert_eq!(arena.len(handle), 3);
681 assert_eq!(arena.get(handle, &key1), Some(value1));
682 assert_eq!(arena.get(handle, &key2), Some(value2));
683 assert_eq!(arena.get(handle, &key3), Some(value3));
684 }
685
686 #[test]
687 fn test_resize_on_load_factor() {
688 let mut arena = HashMapArena::new();
689 let handle = arena.new_hashmap_with_capacity(4);
690
691 for i in 0..6 {
693 let key = create_test_value(i);
694 let value = create_test_value(i * 10);
695 arena.insert(handle, key, value);
696 }
697
698 assert_eq!(arena.len(handle), 6);
699
700 for i in 0..6 {
702 let key = create_test_value(i);
703 let expected_value = create_test_value(i * 10);
704 assert_eq!(arena.get(handle, &key), Some(expected_value));
705 }
706
707 if let Some(hashmap) = arena.hashmaps.get(handle) {
709 assert!(hashmap.capacity > 4);
710 }
711 }
712
713 #[test]
714 fn test_iterator() {
715 let mut arena = HashMapArena::new();
716 let handle = arena.new_hashmap();
717
718 let test_pairs = vec![
720 (create_test_value(1), create_test_value(10)),
721 (create_test_value(2), create_test_value(20)),
722 (create_test_value(3), create_test_value(30)),
723 ];
724
725 for (key, value) in &test_pairs {
726 arena.insert(handle, *key, *value);
727 }
728
729 let mut collected: Vec<_> = arena.iter(handle).collect();
731 collected.sort_by_key(|(k, _)| match k.as_number() {
732 Some(n) => n as i32,
733 _ => 0,
734 });
735
736 assert_eq!(collected.len(), 3);
737 assert_eq!(collected[0], (create_test_value(1), create_test_value(10)));
738 assert_eq!(collected[1], (create_test_value(2), create_test_value(20)));
739 assert_eq!(collected[2], (create_test_value(3), create_test_value(30)));
740 }
741
742 #[test]
743 fn test_iterator_empty_hashmap() {
744 let arena = HashMapArena::new();
745 let handle = HashMapHandle::default();
746
747 let collected: Vec<_> = arena.iter(handle).collect();
748 assert!(collected.is_empty());
749 }
750
751 #[test]
752 fn test_iterator_after_removals() {
753 let mut arena = HashMapArena::new();
754 let handle = arena.new_hashmap();
755
756 for i in 0..5 {
758 let key = create_test_value(i);
759 let value = create_test_value(i * 10);
760 arena.insert(handle, key, value);
761 }
762
763 arena.remove(handle, &create_test_value(1));
765 arena.remove(handle, &create_test_value(3));
766
767 let mut collected: Vec<_> = arena.iter(handle).collect();
769 collected.sort_by_key(|(k, _)| match k.as_number() {
770 Some(n) => n as i32,
771 _ => 0,
772 });
773
774 assert_eq!(collected.len(), 3);
775 assert_eq!(collected[0], (create_test_value(0), create_test_value(0)));
776 assert_eq!(collected[1], (create_test_value(2), create_test_value(20)));
777 assert_eq!(collected[2], (create_test_value(4), create_test_value(40)));
778 }
779
780 #[test]
781 fn test_stress_insertions_and_lookups() {
782 let mut arena = HashMapArena::new();
783 let handle = arena.new_hashmap();
784
785 const NUM_ITEMS: i32 = 100;
786
787 for i in 0..NUM_ITEMS {
789 let key = create_test_value(i);
790 let value = create_test_value(i * 7); arena.insert(handle, key, value);
792 }
793
794 assert_eq!(arena.len(handle), NUM_ITEMS as usize);
795
796 for i in 0..NUM_ITEMS {
798 let key = create_test_value(i);
799 let expected_value = create_test_value(i * 7);
800 assert_eq!(arena.get(handle, &key), Some(expected_value));
801 }
802
803 for i in 0..NUM_ITEMS / 2 {
805 let key = create_test_value(i * 2); arena.remove(handle, &key);
807 }
808
809 assert_eq!(arena.len(handle), (NUM_ITEMS - NUM_ITEMS / 2) as usize);
810
811 for i in 0..NUM_ITEMS {
813 let key = create_test_value(i);
814 let expected_value = create_test_value(i * 7);
815
816 if i % 2 == 0 && i < NUM_ITEMS {
817 assert_eq!(arena.get(handle, &key), None);
819 } else {
820 assert_eq!(arena.get(handle, &key), Some(expected_value));
822 }
823 }
824 }
825
826 #[test]
827 fn test_different_value_types() {
828 let mut arena = HashMapArena::new();
829 let handle = arena.new_hashmap();
830
831 arena.insert(handle, Value::nil(), Value::boolean(true));
833 arena.insert(handle, Value::boolean(false), Value::number(42.0));
834 arena.insert(handle, Value::number(123.0), Value::nil());
835
836 assert_eq!(arena.get(handle, &Value::nil()), Some(Value::boolean(true)));
837 assert_eq!(
838 arena.get(handle, &Value::boolean(false)),
839 Some(Value::number(42.0))
840 );
841 assert_eq!(arena.get(handle, &Value::number(123.0)), Some(Value::nil()));
842
843 assert_eq!(arena.len(handle), 3);
844 }
845
846 #[test]
847 fn test_delete_hashmap() {
848 let mut arena = HashMapArena::new();
849 let handle = arena.new_hashmap();
850
851 for i in 0..5 {
853 let key = create_test_value(i);
854 let value = create_test_value(i * 10);
855 arena.insert(handle, key, value);
856 }
857
858 assert_eq!(arena.len(handle), 5);
859 assert!(!arena.is_empty(handle));
860
861 let deleted = arena.delete_hashmap(handle);
863 assert!(deleted);
864
865 assert_eq!(arena.len(handle), 0);
867 assert!(arena.is_empty(handle));
868 assert_eq!(arena.get(handle, &create_test_value(0)), None);
869 }
870
871 #[test]
872 fn test_delete_nonexistent_hashmap() {
873 let mut arena = HashMapArena::new();
874 let invalid_handle = HashMapHandle::default();
875
876 let deleted = arena.delete_hashmap(invalid_handle);
878 assert!(!deleted);
879 }
880
881 #[test]
882 fn test_delete_hashmap_with_multiple_chunks() {
883 let mut arena = HashMapArena::new();
884 let handle = arena.new_hashmap_with_capacity(4); for i in 0..20 {
888 let key = create_test_value(i);
889 let value = create_test_value(i * 10);
890 arena.insert(handle, key, value);
891 }
892
893 let initial_chunk_count = arena.chunks.len();
894 assert!(initial_chunk_count > 1); let deleted = arena.delete_hashmap(handle);
898 assert!(deleted);
899
900 assert_eq!(arena.len(handle), 0);
904 assert!(arena.is_empty(handle));
905 }
906
907 #[test]
908 fn test_delete_hashmap_preserves_other_hashmaps() {
909 let mut arena = HashMapArena::new();
910 let handle1 = arena.new_hashmap();
911 let handle2 = arena.new_hashmap();
912
913 for i in 0..3 {
915 let key = create_test_value(i);
916 let value1 = create_test_value(i * 10);
917 let value2 = create_test_value(i * 20);
918
919 arena.insert(handle1, key, value1);
920 arena.insert(handle2, key, value2);
921 }
922
923 assert_eq!(arena.len(handle1), 3);
924 assert_eq!(arena.len(handle2), 3);
925
926 let deleted = arena.delete_hashmap(handle1);
928 assert!(deleted);
929
930 assert_eq!(arena.len(handle1), 0);
932 assert!(arena.is_empty(handle1));
933 assert_eq!(arena.get(handle1, &create_test_value(0)), None);
934
935 assert_eq!(arena.len(handle2), 3);
937 assert!(!arena.is_empty(handle2));
938 for i in 0..3 {
939 let key = create_test_value(i);
940 let expected_value = create_test_value(i * 20);
941 assert_eq!(arena.get(handle2, &key), Some(expected_value));
942 }
943 }
944
945 #[test]
946 fn test_delete_hashmap_memory_efficiency() {
947 let mut arena = HashMapArena::new();
948 let handle = arena.new_hashmap();
949
950 for i in 0..50 {
952 let key = create_test_value(i);
953 let value = create_test_value(i * 10);
954 arena.insert(handle, key, value);
955 }
956
957 let bytes_before = arena.get_allocated_bytes();
958 assert!(bytes_before > 0);
959
960 arena.delete_hashmap(handle);
962
963 let bytes_after = arena.get_allocated_bytes();
964
965 assert!(bytes_after < bytes_before);
968 }
969
970 #[test]
971 fn test_garbage_collection() {
972 let mut arena = HashMapArena::new();
973
974 let handle1 = arena.new_hashmap();
976 let handle2 = arena.new_hashmap();
977 let handle3 = arena.new_hashmap();
978
979 for i in 0..5 {
981 let key = create_test_value(i);
982 let value = create_test_value(i * 10);
983 arena.insert(handle1, key, value);
984 arena.insert(handle2, key, value);
985 arena.insert(handle3, key, value);
986 }
987
988 assert_eq!(arena.len(handle1), 5);
989 assert_eq!(arena.len(handle2), 5);
990 assert_eq!(arena.len(handle3), 5);
991
992 arena.mark_hashmap(handle1);
994 arena.mark_hashmap(handle2);
995 arena.collect_garbage();
999
1000 assert_eq!(arena.len(handle1), 5);
1002 assert_eq!(arena.len(handle2), 5);
1003 assert_eq!(
1004 arena.get(handle1, &create_test_value(0)),
1005 Some(create_test_value(0))
1006 );
1007 assert_eq!(
1008 arena.get(handle2, &create_test_value(0)),
1009 Some(create_test_value(0))
1010 );
1011
1012 assert_eq!(arena.len(handle3), 0);
1014 assert!(arena.is_empty(handle3));
1015 assert_eq!(arena.get(handle3, &create_test_value(0)), None);
1016 }
1017
1018 #[test]
1019 fn test_garbage_collection_resets_marks() {
1020 let mut arena = HashMapArena::new();
1021 let handle = arena.new_hashmap();
1022
1023 arena.insert(handle, create_test_value(1), create_test_value(10));
1025
1026 arena.mark_hashmap(handle);
1028
1029 if let Some(hashmap) = arena.hashmaps.get(handle) {
1031 assert!(hashmap.is_marked);
1032 }
1033
1034 arena.collect_garbage();
1036
1037 assert_eq!(arena.len(handle), 1);
1039 if let Some(hashmap) = arena.hashmaps.get(handle) {
1040 assert!(!hashmap.is_marked); }
1042 }
1043
1044 #[test]
1045 fn test_copy_into() {
1046 let mut arena = HashMapArena::new();
1047 let source_handle = arena.new_hashmap();
1048 let dest_handle = arena.new_hashmap();
1049
1050 for i in 0..5 {
1052 let key = create_test_value(i);
1053 let value = create_test_value(i * 10);
1054 arena.insert(source_handle, key, value);
1055 }
1056
1057 arena.insert(dest_handle, create_test_value(0), create_test_value(999));
1059 arena.insert(dest_handle, create_test_value(10), create_test_value(100));
1060
1061 assert_eq!(arena.len(source_handle), 5);
1062 assert_eq!(arena.len(dest_handle), 2);
1063
1064 arena.copy_into(source_handle, dest_handle);
1066
1067 assert_eq!(arena.len(dest_handle), 6); for i in 0..5 {
1072 let key = create_test_value(i);
1073 let expected_value = create_test_value(i * 10);
1074 assert_eq!(arena.get(dest_handle, &key), Some(expected_value));
1075 }
1076
1077 assert_eq!(
1079 arena.get(dest_handle, &create_test_value(0)),
1080 Some(create_test_value(0))
1081 );
1082
1083 assert_eq!(
1085 arena.get(dest_handle, &create_test_value(10)),
1086 Some(create_test_value(100))
1087 );
1088
1089 assert_eq!(arena.len(source_handle), 5);
1091 for i in 0..5 {
1092 let key = create_test_value(i);
1093 let expected_value = create_test_value(i * 10);
1094 assert_eq!(arena.get(source_handle, &key), Some(expected_value));
1095 }
1096 }
1097
1098 #[test]
1099 fn test_copy_into_empty_source() {
1100 let mut arena = HashMapArena::new();
1101 let source_handle = arena.new_hashmap();
1102 let dest_handle = arena.new_hashmap();
1103
1104 arena.insert(dest_handle, create_test_value(1), create_test_value(10));
1106
1107 assert_eq!(arena.len(source_handle), 0);
1108 assert_eq!(arena.len(dest_handle), 1);
1109
1110 arena.copy_into(source_handle, dest_handle);
1112
1113 assert_eq!(arena.len(dest_handle), 1);
1115 assert_eq!(
1116 arena.get(dest_handle, &create_test_value(1)),
1117 Some(create_test_value(10))
1118 );
1119 }
1120
1121 #[test]
1122 fn test_copy_into_empty_destination() {
1123 let mut arena = HashMapArena::new();
1124 let source_handle = arena.new_hashmap();
1125 let dest_handle = arena.new_hashmap();
1126
1127 for i in 0..3 {
1129 let key = create_test_value(i);
1130 let value = create_test_value(i * 10);
1131 arena.insert(source_handle, key, value);
1132 }
1133
1134 assert_eq!(arena.len(source_handle), 3);
1135 assert_eq!(arena.len(dest_handle), 0);
1136
1137 arena.copy_into(source_handle, dest_handle);
1139
1140 assert_eq!(arena.len(dest_handle), 3);
1142 for i in 0..3 {
1143 let key = create_test_value(i);
1144 let expected_value = create_test_value(i * 10);
1145 assert_eq!(arena.get(dest_handle, &key), Some(expected_value));
1146 }
1147 }
1148
1149 #[test]
1150 fn test_copy_into_same_handle() {
1151 let mut arena = HashMapArena::new();
1152 let handle = arena.new_hashmap();
1153
1154 for i in 0..3 {
1156 let key = create_test_value(i);
1157 let value = create_test_value(i * 10);
1158 arena.insert(handle, key, value);
1159 }
1160
1161 let original_len = arena.len(handle);
1162
1163 arena.copy_into(handle, handle);
1165
1166 assert_eq!(arena.len(handle), original_len);
1168 for i in 0..3 {
1169 let key = create_test_value(i);
1170 let expected_value = create_test_value(i * 10);
1171 assert_eq!(arena.get(handle, &key), Some(expected_value));
1172 }
1173 }
1174
1175 #[test]
1176 fn test_copy_into_invalid_handles() {
1177 let mut arena = HashMapArena::new();
1178 let valid_handle = arena.new_hashmap();
1179 let invalid_handle = HashMapHandle::default();
1180
1181 arena.insert(valid_handle, create_test_value(1), create_test_value(10));
1183
1184 arena.copy_into(invalid_handle, valid_handle);
1186 assert_eq!(arena.len(valid_handle), 1);
1187
1188 arena.copy_into(valid_handle, invalid_handle);
1190 assert_eq!(arena.len(valid_handle), 1);
1191 assert_eq!(arena.len(invalid_handle), 0);
1192 }
1193}