1use crate::arena::Arena;
2use crate::constants::{BUCKET_NUMBER, BUCKET_RSHIFT};
3use crate::entry::{Entries, Entry};
4use ahash::RandomState;
5use parking_lot::Mutex;
6use std::fmt;
7use std::fmt::Formatter;
8use std::hash::{BuildHasher, Hasher};
9
10pub struct Repository {
20 buckets: [Bucket; BUCKET_NUMBER],
21}
22
23impl Repository {
24 pub fn new() -> Self {
37 Self {
38 buckets: [(); BUCKET_NUMBER].map(|_| Bucket::default()),
39 }
40 }
41
42 pub fn allocated_memory(&self) -> usize {
54 self.buckets
55 .iter()
56 .enumerate()
57 .map(|(_, b)| {
58 let b = b.0.lock();
59 b.entries.allocated_memory() + b.arena.allocated_memory()
60 })
61 .sum()
62 }
63}
64
65impl Repository {
66 pub(crate) fn get_or_insert(&self, string: &str) -> Entry {
67 let hash = Self::get_hash(string);
68 self.buckets[Self::determine_bucket(hash)]
69 .0
70 .lock()
71 .get_or_insert(hash, string)
72 }
73}
74
75impl Repository {
76 fn get_hash(string: &str) -> u64 {
77 static RANDOM: RandomState =
78 RandomState::with_seeds(0x01230456, 0x04560789, 0x07890123, 0x02580137);
79 let mut hasher = RANDOM.build_hasher();
80 hasher.write(string.as_bytes());
81 hasher.finish()
82 }
83
84 const fn determine_bucket(hash: u64) -> usize {
85 (hash >> BUCKET_RSHIFT) as usize
86 }
87}
88
89impl Default for Repository {
90 fn default() -> Self {
92 Self::new()
93 }
94}
95
96impl fmt::Debug for Repository {
97 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
98 f.debug_struct("Repository").finish()
99 }
100}
101
102#[repr(align(32))]
103#[derive(Default)]
104struct Bucket(Mutex<BucketImpl>);
105
106#[derive(Default)]
108struct BucketImpl {
109 arena: Arena,
110 entries: Entries,
111}
112
113impl BucketImpl {
114 #[inline]
115 fn get_or_insert(&mut self, hash: u64, string: &str) -> Entry {
116 self.entries
117 .get_or_insert(hash, string, || Entry(self.arena.alloc_str(hash, string)))
118 }
119}