Files
@ 33ea10021de4
Branch filter:
Location: CSY/reowolf/src/protocol/containers.rs - annotation
33ea10021de4
3.6 KiB
application/rls-services+xml
refactored identifiers, initial symbol table implementation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 33ea10021de4 | /// Containers.rs
///
/// Contains specialized containers for the parser/compiler
const PAGE_SIZE: usize = 4096;
struct StringPage {
buffer: [u8; PAGE_SIZE],
remaining: usize,
next_page: Option<Box<StringPage>>,
}
impl StringPage {
fn new() -> Self{
let res = Self{
buffer: [0; PAGE_SIZE],
remaining: PAGE_SIZE,
next_page: None
};
res
}
}
/// Custom allocator for strings that are copied and remain valid during the
/// complete compilation phase. May perform multiple allocations but the
/// previously allocated strings remain valid. Because we will usually allocate
/// quite a number of these we will allocate a buffer upon construction of the
/// StringAllocator.
pub(crate) struct StringAllocator {
first_page: Box<StringPage>,
last_page: *mut StringPage,
}
impl StringAllocator {
pub(crate) fn new() -> StringAllocator {
let mut page = Box::new(StringPage::new());
let page_ptr = unsafe { page.as_mut() as *mut StringPage };
StringAllocator{
first_page: page,
last_page: page_ptr,
}
}
pub(crate) fn alloc(&mut self, data: &[u8]) -> Result<&'static str, String> {
let data_len = data.len();
if data_len > PAGE_SIZE {
return Err(format!(
"string is too large ({} bytes exceeds the maximum of {})",
data_len, PAGE_SIZE
));
}
// Because we're doing a copy anyway, we might as well perform the
// UTF-8 checking now. Such that it is safe to do an unchecked
// `from_utf8_unchecked` later.
let data = std::str::from_utf8(data);
if let Err(_) = data {
return Err(format!("invalid utf8-string"));
}
let data = data.unwrap();
unsafe {
if data_len > (*self.last_page).remaining {
// Allocate new page
let mut new_page = Box::new(StringPage::new());
let new_page_ptr = new_page.as_mut() as *mut StringPage;
(*self.last_page).next_page = Some(new_page);
self.last_page = new_page_ptr;
}
let remaining = (*self.last_page).remaining;
debug_assert!(data_len <= remaining);
let start = PAGE_SIZE - remaining;
(*self.last_page).buffer[start..start+data_len].copy_from_slice(data.as_bytes());
(*self.last_page).remaining -= data_len;
Ok(std::str::from_utf8_unchecked(&(*self.last_page).buffer[start..start+data_len]))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_alloc() {
// Make sure pointers are somewhat correct
let mut alloc = StringAllocator::new();
assert!(alloc.first_page.next_page.is_none());
assert_eq!(alloc.first_page.as_ref() as *const StringPage, alloc.last_page);
let input = "I am a simple static string";
let filler = " ".repeat(PAGE_SIZE - input.len());
let ref_first = alloc.alloc(input.as_bytes()).expect("alloc first");
let ref_filler = alloc.alloc(filler.as_bytes()).expect("alloc filler");
let ref_second = alloc.alloc(input.as_bytes()).expect("alloc second");
assert!(alloc.first_page.next_page.is_some());
assert!(alloc.first_page.next_page.as_ref().unwrap().next_page.is_none());
let last_page_ptr = alloc.first_page.next_page.as_ref().unwrap().as_ref() as *const StringPage;
assert_eq!(last_page_ptr, alloc.last_page);
assert_eq!(ref_first, input);
assert_eq!(ref_filler, filler);
assert_eq!(ref_second, input);
}
}
|