anathema_strings/storage/
transaction.rs

1use 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    /// Add a slice with the `'slice` lifetime
17    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        // Steps
27        // * Find available storage in the free list that can house our bytes
28        // * If no space is available then append this (remember to pad)
29        // * Only need to care about padding when there is no free region
30        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        // perform special case region pop ONLY if the
41        // len is larger than BUCKET_SIZE * 4
42        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        // No free region so make a new one
53        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}