1use super::{Bucket, Key};
18use ahash::RandomState;
19use crossbeam_skiplist::{map::Entry, SkipMap};
20use flurry::HashMap;
21
22pub struct Compact<T>(Box<[SkipMap<Key, Bucket<T>>]>);
25
26impl<T: Send + 'static> Compact<T> {
27 pub fn new(total_items: usize, items_per_shard: usize) -> Self {
29 assert!(items_per_shard > 0);
30
31 let shards = std::cmp::max(total_items / items_per_shard, 1);
32 let mut shard_array = vec![];
33 for _ in 0..shards {
34 shard_array.push(SkipMap::new());
35 }
36 Self(shard_array.into_boxed_slice())
37 }
38
39 pub fn get(&self, key: &Key) -> Option<Entry<'_, Key, Bucket<T>>> {
40 let shard = *key as usize % self.0.len();
41 self.0[shard].get(key)
42 }
43
44 pub fn get_map<V, F: FnOnce(Entry<Key, Bucket<T>>) -> V>(&self, key: &Key, f: F) -> Option<V> {
45 let v = self.get(key);
46 v.map(f)
47 }
48
49 fn insert(&self, key: Key, value: Bucket<T>) -> Option<()> {
50 let shard = key as usize % self.0.len();
51 let removed = self.0[shard].remove(&key);
52 self.0[shard].insert(key, value);
53 removed.map(|_| ())
54 }
55
56 fn remove(&self, key: &Key) {
57 let shard = *key as usize % self.0.len();
58 (&self.0)[shard].remove(key);
59 }
60}
61
62pub struct Fast<T>(HashMap<Key, Bucket<T>, RandomState>);
64
65impl<T: Send + Sync> Fast<T> {
66 pub fn new(total_items: usize) -> Self {
67 Self(HashMap::with_capacity_and_hasher(
68 total_items,
69 RandomState::new(),
70 ))
71 }
72
73 pub fn get_map<V, F: FnOnce(&Bucket<T>) -> V>(&self, key: &Key, f: F) -> Option<V> {
74 let pinned = self.0.pin();
75 let v = pinned.get(key);
76 v.map(f)
77 }
78
79 fn insert(&self, key: Key, value: Bucket<T>) -> Option<()> {
80 let pinned = self.0.pin();
81 pinned.insert(key, value).map(|_| ())
82 }
83
84 fn remove(&self, key: &Key) {
85 let pinned = self.0.pin();
86 pinned.remove(key);
87 }
88}
89
90pub enum Buckets<T> {
91 Fast(Box<Fast<T>>),
92 Compact(Compact<T>),
93}
94
95impl<T: Send + Sync + 'static> Buckets<T> {
96 pub fn new_fast(items: usize) -> Self {
97 Self::Fast(Box::new(Fast::new(items)))
98 }
99
100 pub fn new_compact(items: usize, items_per_shard: usize) -> Self {
101 Self::Compact(Compact::new(items, items_per_shard))
102 }
103
104 pub fn insert(&self, key: Key, value: Bucket<T>) -> Option<()> {
105 match self {
106 Self::Compact(c) => c.insert(key, value),
107 Self::Fast(f) => f.insert(key, value),
108 }
109 }
110
111 pub fn remove(&self, key: &Key) {
112 match self {
113 Self::Compact(c) => c.remove(key),
114 Self::Fast(f) => f.remove(key),
115 }
116 }
117
118 pub fn get_map<V, F: FnOnce(&Bucket<T>) -> V>(&self, key: &Key, f: F) -> Option<V> {
119 match self {
120 Self::Compact(c) => c.get_map(key, |v| f(v.value())),
121 Self::Fast(c) => c.get_map(key, f),
122 }
123 }
124
125 #[cfg(test)]
126 pub fn get_queue(&self, key: &Key) -> Option<bool> {
127 self.get_map(key, |v| v.queue.is_main())
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 #[test]
136 fn test_fast() {
137 let fast = Buckets::new_fast(10);
138
139 assert!(fast.get_map(&1, |_| ()).is_none());
140
141 let bucket = Bucket {
142 queue: crate::Location::new_small(),
143 weight: 1,
144 uses: Default::default(),
145 data: 1,
146 };
147 fast.insert(1, bucket);
148
149 assert_eq!(fast.get_map(&1, |v| v.data), Some(1));
150
151 fast.remove(&1);
152 assert!(fast.get_map(&1, |_| ()).is_none());
153 }
154
155 #[test]
156 fn test_compact() {
157 let compact = Buckets::new_compact(10, 2);
158
159 assert!(compact.get_map(&1, |_| ()).is_none());
160
161 let bucket = Bucket {
162 queue: crate::Location::new_small(),
163 weight: 1,
164 uses: Default::default(),
165 data: 1,
166 };
167 compact.insert(1, bucket);
168
169 assert_eq!(compact.get_map(&1, |v| v.data), Some(1));
170
171 compact.remove(&1);
172 assert!(compact.get_map(&1, |_| ()).is_none());
173 }
174}