make write_with forward return values, use it to correct partial string handling

This commit is contained in:
Mark Thom
2025-03-15 02:10:56 -07:00
committed by Mark Thom
parent 2ad870c740
commit eef7b06919
3 changed files with 79 additions and 70 deletions

View File

@@ -183,7 +183,7 @@ impl PStrSegmentCmpResult {
#[derive(Debug)] #[derive(Debug)]
pub struct PStrWriteInfo { pub struct PStrWriteInfo {
pstr_loc: usize, cell: HeapCellValue,
} }
#[derive(Debug)] #[derive(Debug)]
@@ -414,29 +414,40 @@ pub struct HeapWriter<'a> {
heap_byte_len: &'a mut usize, heap_byte_len: &'a mut usize,
} }
pub(crate) struct HeapSectionWriteResult<R> {
pub(crate) bytes_written: usize,
pub(crate) result: R,
}
impl<'a> HeapWriter<'a> { impl<'a> HeapWriter<'a> {
#[allow(dead_code)] #[allow(dead_code)]
pub(crate) fn write_with_error_handling<E>( pub(crate) fn write_with_error_handling<R, E>(
&mut self, &mut self,
writer: impl FnOnce(&mut ReservedHeapSection) -> Result<(), E>, writer: impl FnOnce(&mut ReservedHeapSection) -> Result<R, E>,
) -> Result<usize, E> { ) -> Result<HeapSectionWriteResult<R>, E> {
let old_section_cell_len = self.section.heap_cell_len; let old_section_cell_len = self.section.heap_cell_len;
writer(&mut self.section)?; let result = writer(&mut self.section)?;
*self.heap_byte_len = heap_index!(self.section.heap_cell_len); *self.heap_byte_len = heap_index!(self.section.heap_cell_len);
// return the number of bytes written // return the number of bytes written
Ok(heap_index!( Ok(HeapSectionWriteResult {
self.section.heap_cell_len - old_section_cell_len bytes_written: heap_index!(self.section.heap_cell_len - old_section_cell_len),
)) result,
})
} }
pub(crate) fn write_with(&mut self, writer: impl FnOnce(&mut ReservedHeapSection)) -> usize { pub(crate) fn write_with<R>(
&mut self,
writer: impl FnOnce(&mut ReservedHeapSection) -> R,
) -> HeapSectionWriteResult<R> {
let old_section_cell_len = self.section.heap_cell_len; let old_section_cell_len = self.section.heap_cell_len;
writer(&mut self.section); let result = writer(&mut self.section);
*self.heap_byte_len = heap_index!(self.section.heap_cell_len); *self.heap_byte_len = heap_index!(self.section.heap_cell_len);
// return the number of bytes written HeapSectionWriteResult {
heap_index!(self.section.heap_cell_len - old_section_cell_len) bytes_written: heap_index!(self.section.heap_cell_len - old_section_cell_len),
result,
}
} }
#[inline] #[inline]
@@ -854,20 +865,11 @@ impl Heap {
pub fn allocate_pstr(&mut self, src: &str) -> Result<Option<PStrWriteInfo>, usize> { pub fn allocate_pstr(&mut self, src: &str) -> Result<Option<PStrWriteInfo>, usize> {
let size_in_heap = Self::compute_pstr_size(src); let size_in_heap = Self::compute_pstr_size(src);
let mut writer = self.reserve(size_in_heap)?;
let HeapSectionWriteResult { result, .. } =
writer.write_with(|section| section.push_pstr(src));
let pstr_loc = heap_index!(self.cell_len()); Ok(result.map(|cell| PStrWriteInfo { cell }))
Ok(if size_in_heap > 0 {
let mut writer = self.reserve(size_in_heap)?;
writer.write_with(|section| {
section.push_pstr(src);
});
Some(PStrWriteInfo { pstr_loc })
} else {
None
})
} }
pub const fn heap_cell_alignment() -> usize { pub const fn heap_cell_alignment() -> usize {
@@ -1053,7 +1055,8 @@ impl Heap {
move |heap| { move |heap| {
let mut writer = heap.reserve(size)?; let mut writer = heap.reserve(size)?;
let heap_byte_len = *writer.heap_byte_len; let heap_byte_len = *writer.heap_byte_len;
let bytes_written = writer.write_with(&mut functor_writer); let HeapSectionWriteResult { bytes_written, .. } =
writer.write_with(&mut functor_writer);
Ok(if cell_index!(bytes_written) > 1 { Ok(if cell_index!(bytes_written) > 1 {
str_loc_as_cell!(cell_index!(heap_byte_len)) str_loc_as_cell!(cell_index!(heap_byte_len))
@@ -1108,19 +1111,18 @@ impl MachineState {
pub(crate) fn allocate_pstr(&mut self, src: &str) -> Result<HeapCellValue, usize> { pub(crate) fn allocate_pstr(&mut self, src: &str) -> Result<HeapCellValue, usize> {
match self.heap.allocate_pstr(src)? { match self.heap.allocate_pstr(src)? {
None => Ok(empty_list_as_cell!()), None => Ok(empty_list_as_cell!()),
Some(PStrWriteInfo { pstr_loc, .. }) => Ok(pstr_loc_as_cell!(pstr_loc)), Some(PStrWriteInfo { cell }) => Ok(cell),
} }
} }
// note that allocate_cstr does emit a tail cell to the string // note that allocate_cstr emits a tail cell to the string (completing it with the empty list)
// (completing it with the empty list), allocate_pstr does not, in // unlike any version of allocate_pstr.
// any incarnation.
pub(crate) fn allocate_cstr(&mut self, src: &str) -> Result<HeapCellValue, usize> { pub(crate) fn allocate_cstr(&mut self, src: &str) -> Result<HeapCellValue, usize> {
match self.heap.allocate_pstr(src)? { match self.heap.allocate_pstr(src)? {
None => Ok(empty_list_as_cell!()), None => Ok(empty_list_as_cell!()),
Some(PStrWriteInfo { pstr_loc, .. }) => { Some(PStrWriteInfo { cell }) => {
self.heap.push_cell(empty_list_as_cell!())?; self.heap.push_cell(empty_list_as_cell!())?;
Ok(pstr_loc_as_cell!(pstr_loc)) Ok(cell)
} }
} }
} }
@@ -1281,17 +1283,3 @@ pub(crate) fn to_local_code_ptr(heap: &Heap, addr: HeapCellValue) -> Option<usiz
} }
) )
} }
#[cfg(test)]
mod test {
use super::*;
#[test]
fn heap_manipulation() {
let mut heap = Heap::new();
for idx in 0 .. 10 {
heap.push_cell(heap_loc_as_cell!(idx)).unwrap();
}
}
}

View File

@@ -289,10 +289,13 @@ impl Ball {
while pstr_threshold < heap_index!(self.stub.cell_len()) { while pstr_threshold < heap_index!(self.stub.cell_len()) {
let HeapStringScan { string, tail_idx } = self.stub.scan_slice_to_str(pstr_threshold); let HeapStringScan { string, tail_idx } = self.stub.scan_slice_to_str(pstr_threshold);
pstr_threshold += dest_writer.write_with(|section| { pstr_threshold += dest_writer
section.push_pstr(string).unwrap(); .write_with(|section| {
section.push_cell(self.stub[tail_idx] - diff); if section.push_pstr(string).is_some() {
}); section.push_cell(self.stub[tail_idx] - diff);
}
})
.bytes_written;
} }
Ok(h) Ok(h)

View File

@@ -662,24 +662,36 @@ impl<'a> Parser<'a> {
match as_partial_string(&self.terms, head, tail) { match as_partial_string(&self.terms, head, tail) {
Some((string_buf, tail_opt)) => { Some((string_buf, tail_opt)) => {
let bytes_written = self.terms.write_with(|section| { let HeapSectionWriteResult { bytes_written, .. } =
let pstr_cell = section.push_pstr(&string_buf).unwrap(); self.terms.write_with(|section| {
section.push_cell(tail_opt.unwrap_or(empty_list_as_cell!())); if let Some(pstr_cell) = section.push_pstr(&string_buf) {
section.push_cell(pstr_cell); section
}); .push_cell(tail_opt.unwrap_or(empty_list_as_cell!()));
section.push_cell(pstr_cell);
} else {
section.push_cell(empty_list_as_cell!());
}
});
let heap_loc = cell_index!(bytes_written) - 1 + cell_len; if cell_index!(bytes_written) > 1 {
TokenType::Term {
TokenType::Term { heap_loc: heap_loc_as_cell!(
heap_loc: heap_loc_as_cell!(heap_loc), cell_index!(bytes_written) - 1 + cell_len
),
}
} else {
TokenType::Term {
heap_loc: heap_loc_as_cell!(cell_len),
}
} }
} }
None => { None => {
let bytes_written = self.terms.write_with(|section| { let HeapSectionWriteResult { bytes_written, .. } =
section.push_cell(head); self.terms.write_with(|section| {
section.push_cell(tail); section.push_cell(head);
section.push_cell(list_loc_as_cell!(term_idx)); section.push_cell(tail);
}); section.push_cell(list_loc_as_cell!(term_idx));
});
TokenType::Term { TokenType::Term {
heap_loc: heap_loc_as_cell!( heap_loc: heap_loc_as_cell!(
@@ -911,13 +923,19 @@ impl<'a> Parser<'a> {
Some((string_buf, tail_opt)) => { Some((string_buf, tail_opt)) => {
self.terms.truncate(pre_terms_len); self.terms.truncate(pre_terms_len);
let bytes_written = self.terms.write_with(|section| { let HeapSectionWriteResult { bytes_written, .. } =
let pstr_cell = section.push_pstr(&string_buf).unwrap(); self.terms.write_with(|section| {
section.push_cell(tail_opt.unwrap_or(empty_list_as_cell!())); if let Some(pstr_cell) = section.push_pstr(&string_buf) {
section.push_cell(pstr_cell); section.push_cell(tail_opt.unwrap_or(empty_list_as_cell!()));
}); section.push_cell(pstr_cell);
}
});
heap_loc_as_cell!(pre_terms_len + cell_index!(bytes_written) - 1) if bytes_written > 0 {
heap_loc_as_cell!(pre_terms_len + cell_index!(bytes_written) - 1)
} else {
empty_list_as_cell!()
}
} }
None => { None => {
heap_loc_as_cell!(list_loc) // head_term heap_loc_as_cell!(list_loc) // head_term