casc_storage/index/
sorted_index.rs1use crate::types::{ArchiveLocation, EKey};
4use std::collections::BTreeMap;
5
6#[derive(Debug, Clone)]
8pub struct SortedIndex {
9 entries: BTreeMap<EKey, ArchiveLocation>,
11 sorted_keys: Option<Vec<EKey>>,
13}
14
15impl SortedIndex {
16 pub fn new() -> Self {
18 Self {
19 entries: BTreeMap::new(),
20 sorted_keys: None,
21 }
22 }
23
24 pub fn with_capacity(_capacity: usize) -> Self {
26 Self::new()
28 }
29
30 pub fn insert(&mut self, key: EKey, location: ArchiveLocation) {
32 self.entries.insert(key, location);
33 self.sorted_keys = None;
35 }
36
37 pub fn lookup(&self, key: &EKey) -> Option<&ArchiveLocation> {
39 self.entries.get(key)
40 }
41
42 pub fn range(
44 &self,
45 start: &EKey,
46 end: &EKey,
47 ) -> impl Iterator<Item = (&EKey, &ArchiveLocation)> {
48 self.entries.range(start..=end)
49 }
50
51 pub fn lower_bound(&self, key: &EKey) -> Option<(&EKey, &ArchiveLocation)> {
53 self.entries.range(key..).next()
54 }
55
56 pub fn upper_bound(&self, key: &EKey) -> Option<(&EKey, &ArchiveLocation)> {
58 self.entries.range(..=key).next_back()
59 }
60
61 pub fn entries(&self) -> impl Iterator<Item = (&EKey, &ArchiveLocation)> {
63 self.entries.iter()
64 }
65
66 pub fn len(&self) -> usize {
68 self.entries.len()
69 }
70
71 pub fn is_empty(&self) -> bool {
73 self.entries.is_empty()
74 }
75
76 pub fn clear(&mut self) {
78 self.entries.clear();
79 self.sorted_keys = None;
80 }
81
82 pub fn sorted_keys(&mut self) -> &[EKey] {
84 if self.sorted_keys.is_none() {
85 self.sorted_keys = Some(self.entries.keys().copied().collect());
86 }
87 self.sorted_keys.as_ref().unwrap()
88 }
89
90 pub fn extend<I>(&mut self, iter: I)
92 where
93 I: IntoIterator<Item = (EKey, ArchiveLocation)>,
94 {
95 self.entries.extend(iter);
96 self.sorted_keys = None;
97 }
98
99 pub fn from_hashmap(map: std::collections::HashMap<EKey, ArchiveLocation>) -> Self {
101 let mut index = Self::new();
102 index.extend(map);
103 index
104 }
105
106 pub fn into_btree_map(self) -> BTreeMap<EKey, ArchiveLocation> {
108 self.entries
109 }
110}
111
112impl Default for SortedIndex {
113 fn default() -> Self {
114 Self::new()
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121
122 #[test]
123 fn test_sorted_index_operations() {
124 let mut index = SortedIndex::new();
125
126 let key1 = EKey::new([1; 16]);
128 let key2 = EKey::new([2; 16]);
129 let key3 = EKey::new([3; 16]);
130
131 let loc1 = ArchiveLocation {
132 archive_id: 1,
133 offset: 100,
134 size: 50,
135 };
136
137 let loc2 = ArchiveLocation {
138 archive_id: 2,
139 offset: 200,
140 size: 60,
141 };
142
143 let loc3 = ArchiveLocation {
144 archive_id: 3,
145 offset: 300,
146 size: 70,
147 };
148
149 index.insert(key2, loc2);
151 index.insert(key1, loc1);
152 index.insert(key3, loc3);
153
154 assert_eq!(index.lookup(&key1), Some(&loc1));
156 assert_eq!(index.lookup(&key2), Some(&loc2));
157 assert_eq!(index.lookup(&key3), Some(&loc3));
158
159 let key4 = EKey::new([4; 16]);
161 assert_eq!(index.lookup(&key4), None);
162
163 assert_eq!(index.len(), 3);
165
166 let range: Vec<_> = index.range(&key1, &key2).collect();
168 assert_eq!(range.len(), 2);
169
170 let lower = index.lower_bound(&key2);
172 assert!(lower.is_some());
173 assert_eq!(lower.unwrap().0, &key2);
174 }
175
176 #[test]
177 fn test_sorted_order() {
178 let mut index = SortedIndex::new();
179
180 for i in [5u8, 2, 8, 1, 9, 3, 7, 4, 6] {
182 let mut key_bytes = [0u8; 16];
183 key_bytes[0] = i;
184 let key = EKey::new(key_bytes);
185 let loc = ArchiveLocation {
186 archive_id: i as u16,
187 offset: (i as u64) * 100,
188 size: 50,
189 };
190 index.insert(key, loc);
191 }
192
193 let keys: Vec<_> = index.entries().map(|(k, _)| *k).collect();
195 for i in 1..keys.len() {
196 assert!(keys[i - 1] < keys[i], "Keys should be in sorted order");
197 }
198 }
199}