anathema_strings/storage/
transaction.rs1use std::fmt::Write;
2
3use super::{END, Storage};
4use crate::region::Region;
5use crate::{BUCKET_SIZE, StrIndex};
6
7pub struct Transaction<'a, 'slice> {
8 storage: &'a mut Storage<'slice>,
9}
10
11impl<'a, 'slice> Transaction<'a, 'slice> {
12 pub(super) fn new(storage: &'a mut Storage<'slice>) -> Self {
13 Self { storage }
14 }
15
16 pub fn add_slice(&mut self, slice: &'slice str) {
18 let key = self.storage.slices.insert(slice);
19 assert!(key != u16::MAX);
20 self.storage.buffer.extend_from_slice(&key.to_ne_bytes());
21 }
22
23 pub fn commit(mut self) -> StrIndex {
24 let len = self.storage.buffer.len();
25
26 let padding = len % BUCKET_SIZE;
31 let size = len + padding;
32
33 let key_range = (size / BUCKET_SIZE).min(END)..END;
34 for i in key_range {
35 let storage = self.get_storage(i);
36 let Some(region) = storage.pop() else { continue };
37 return region.apply(&mut self.storage.inner, &mut self.storage.buffer, len);
38 }
39
40 if len > BUCKET_SIZE * 4 {
43 let variable_storage = self.get_storage(END - 1);
44 variable_storage.sort_unstable_by(|a, b| a.len.cmp(&b.len));
45
46 if let Some(idx) = variable_storage.iter().position(|region| region.len >= len as u32) {
47 let region = variable_storage.remove(idx);
48 return region.apply(&mut self.storage.inner, &mut self.storage.buffer, len);
49 }
50 }
51
52 let start = self.storage.inner.len();
54 self.storage.inner.extend_from_slice(&self.storage.buffer[..len]);
55
56 self.storage.inner.resize(self.storage.inner.len() + padding, 0);
57 StrIndex::new(start, len)
58 }
59
60 fn get_storage(&mut self, index: usize) -> &mut Vec<Region> {
61 self.storage.free.get_mut(index as u8).expect("this is pre-generated")
62 }
63}
64
65impl Write for Transaction<'_, '_> {
66 fn write_str(&mut self, s: &str) -> std::fmt::Result {
67 assert!(s.len() <= u16::MAX as usize);
68 let len = s.len() as u16;
69 self.storage.buffer.extend_from_slice(&[0xFF, 0xFF]);
70 self.storage.buffer.extend_from_slice(&len.to_ne_bytes());
71 self.storage.buffer.extend_from_slice(s.as_bytes());
72 Ok(())
73 }
74}