internment/
container.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
use std::any::Any;
use std::any::TypeId;
use std::hash::{Hash, Hasher};
use std::sync::Mutex;

pub struct TypeHolderSend(Vec<AnySend>);

struct AnySend(Box<dyn Any + Send>);

impl TypeHolderSend {
    pub fn get_type_mut<T: Any + Send + Default>(&mut self) -> &mut T {
        if let Some(i) = self
            .0
            .iter_mut()
            .position(|x| x.0.downcast_mut::<T>().is_some())
        {
            self.0[i].0.downcast_mut().unwrap()
        } else {
            let v: T = Default::default();
            self.0.push(AnySend(Box::new(v)));
            self.0.last_mut().unwrap().0.downcast_mut().unwrap()
        }
    }
    pub const fn new() -> Self {
        TypeHolderSend(Vec::new())
    }
}

const INTERN_CONTAINER_COUNT: usize = 32;
pub struct Arena {
    containers: [Mutex<TypeHolderSend>; INTERN_CONTAINER_COUNT],
}

impl Arena {
    pub const fn new() -> Self {
        const EMPTY: Mutex<TypeHolderSend> = Mutex::new(TypeHolderSend::new());
        Arena {
            containers: [EMPTY; INTERN_CONTAINER_COUNT],
        }
    }

    pub fn with<F, T, R>(&self, f: F) -> R
    where
        F: FnOnce(&mut T) -> R,
        T: Any + Send + Default,
    {
        // Compute the hash of the type.
        fn hash_of_type<T: 'static>() -> u64 {
            // We use very simple hasher, because it is optimized away to a constant:
            // https://rust.godbolt.org/z/4T1fa4GGs
            // which is not true for using `DefaultHasher`:
            // https://rust.godbolt.org/z/qKar1WKfz
            struct HasherForTypeId {
                hash: u64,
            }

            impl Hasher for HasherForTypeId {
                fn write(&mut self, bytes: &[u8]) {
                    // Hash for type only calls `write_u64` once,
                    // but handle this case explicitly to make sure
                    // this code doesn't break if stdlib internals change.

                    for byte in bytes {
                        self.hash = self.hash.wrapping_mul(31).wrapping_add(*byte as u64);
                    }
                }

                fn write_u64(&mut self, v: u64) {
                    self.hash = v;
                }

                fn finish(&self) -> u64 {
                    self.hash
                }
            }

            let mut hasher = HasherForTypeId { hash: 0 };
            TypeId::of::<T>().hash(&mut hasher);
            hasher.finish()
        }

        f(
            self.containers[hash_of_type::<T>() as usize % INTERN_CONTAINER_COUNT]
                .lock()
                .unwrap()
                .get_type_mut(),
        )
    }
}

#[test]
fn test_arena() {
    let arena = Arena::new();
    arena.with(|x: &mut i32| {
        *x = 42;
    });
    arena.with(|x: &mut u32| {
        *x = 137;
    });
    arena.with(|x: &mut i32| {
        assert_eq!(*x, 42);
    });
    arena.with(|x: &mut u32| {
        assert_eq!(*x, 137);
    });
}