properly account for partial string offsets in '$skip_max_list' (#1827)

This commit is contained in:
Mark
2023-06-26 16:32:30 -06:00
parent 0b45d42912
commit a6522d6317
2 changed files with 116 additions and 61 deletions

View File

@@ -799,7 +799,7 @@ pub enum CycleSearchResult {
NotList(usize, HeapCellValue), // the list length until the second argument in the heap NotList(usize, HeapCellValue), // the list length until the second argument in the heap
PartialList(usize, Ref), // the list length (up to max), and an offset into the heap. PartialList(usize, Ref), // the list length (up to max), and an offset into the heap.
ProperList(usize), // the list length. ProperList(usize), // the list length.
PStrLocation(usize, usize), // list length (up to max), the heap address of the PStrOffset PStrLocation(usize, usize, usize), // list length (up to max), the heap address of the PStr, the offset
UntouchedList(usize, usize), // list length (up to max), the address of an uniterated Addr::Lis(address). UntouchedList(usize, usize), // list length (up to max), the address of an uniterated Addr::Lis(address).
UntouchedCStr(Atom, usize), UntouchedCStr(Atom, usize),
} }

View File

@@ -120,6 +120,7 @@ pub struct BrentAlgState {
pub power: usize, pub power: usize,
pub lam: usize, pub lam: usize,
pub pstr_chars: usize, pub pstr_chars: usize,
max_steps: i64,
} }
impl BrentAlgState { impl BrentAlgState {
@@ -130,6 +131,7 @@ impl BrentAlgState {
power: 1, power: 1,
lam: 0, lam: 0,
pstr_chars: 0, pstr_chars: 0,
max_steps: -1,
} }
} }
@@ -161,72 +163,95 @@ impl BrentAlgState {
return self.lam + self.pstr_chars + self.power - 1; return self.lam + self.pstr_chars + self.power - 1;
} }
#[inline(always)]
pub fn exhausted_max_steps(&self) -> bool {
self.max_steps > -1 && self.num_steps() as i64 >= self.max_steps
}
pub fn to_result(mut self, heap: &[HeapCellValue]) -> CycleSearchResult { pub fn to_result(mut self, heap: &[HeapCellValue]) -> CycleSearchResult {
/*
if let Some(var) = heap[self.hare].as_var() { if let Some(var) = heap[self.hare].as_var() {
return CycleSearchResult::PartialList(self.num_steps(), var); return CycleSearchResult::PartialList(self.num_steps(), var);
} }
*/
read_heap_cell!(heap[self.hare], loop {
(HeapCellValueTag::PStrOffset) => { read_heap_cell!(heap[self.hare],
let n = cell_as_fixnum!(heap[self.hare+1]).get_num() as usize; (HeapCellValueTag::PStrOffset) => {
let (pstr_loc, offset) = pstr_loc_and_offset(heap, self.hare);
let offset = offset.get_num() as usize;
let pstr = cell_as_string!(heap[self.hare]); let pstr = cell_as_string!(heap[self.hare]);
self.pstr_chars += pstr.as_str_from(n).chars().count(); self.pstr_chars += pstr.as_str_from(offset).chars().count();
return CycleSearchResult::PStrLocation(self.num_steps(), n); return CycleSearchResult::PStrLocation(self.num_steps(), pstr_loc, offset);
} }
(HeapCellValueTag::Atom, (name, arity)) => { (HeapCellValueTag::PStrLoc, l) => {
return if name == atom!("[]") && arity == 0 { let (_pstr_loc, offset) = pstr_loc_and_offset(heap, l);
CycleSearchResult::ProperList(self.num_steps()) let offset = offset.get_num() as usize;
} else { return CycleSearchResult::PStrLocation(self.num_steps(), l, offset);
CycleSearchResult::NotList(self.num_steps(), heap[self.hare]) }
}; (HeapCellValueTag::Atom, (name, arity)) => {
} return if name == atom!("[]") && arity == 0 {
(HeapCellValueTag::Str, s) => { CycleSearchResult::ProperList(self.num_steps())
let (name, arity) = cell_as_atom_cell!(heap[s]) } else {
.get_name_and_arity(); CycleSearchResult::NotList(self.num_steps(), heap[self.hare])
};
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(heap[s])
.get_name_and_arity();
return if name == atom!("[]") && arity == 0 { return if name == atom!("[]") && arity == 0 {
CycleSearchResult::ProperList(self.num_steps()) CycleSearchResult::ProperList(self.num_steps())
} else { } else {
CycleSearchResult::NotList(self.num_steps(), heap[self.hare]) CycleSearchResult::NotList(self.num_steps(), heap[self.hare])
}; };
} }
(HeapCellValueTag::Lis, l) => { (HeapCellValueTag::Lis, l) => {
return CycleSearchResult::UntouchedList(self.num_steps(), l); return CycleSearchResult::UntouchedList(self.num_steps(), l);
} }
_ => { (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
return CycleSearchResult::NotList(self.num_steps(), heap[self.hare]); if h == self.hare {
} let var = heap[self.hare].as_var().unwrap();
); return CycleSearchResult::PartialList(self.num_steps(), var);
} else {
self.hare = h;
}
}
_ => {
return CycleSearchResult::NotList(self.num_steps(), heap[self.hare]);
}
);
}
} }
fn add_pstr_chars_and_step(&mut self, heap: &[HeapCellValue], h: usize) -> Option<CycleSearchResult> { fn add_pstr_offset_chars(&mut self, heap: &[HeapCellValue], h: usize, offset: usize) -> Option<CycleSearchResult> {
read_heap_cell!(heap[h], read_heap_cell!(heap[h],
(HeapCellValueTag::CStr, cstr_atom) => { (HeapCellValueTag::CStr, cstr_atom) => {
let cstr = PartialString::from(cstr_atom); let cstr = PartialString::from(cstr_atom);
let num_chars = cstr.as_str_from(offset).chars().count();
self.pstr_chars += cstr.as_str_from(0).chars().count(); if self.max_steps == -1 || self.num_steps() + num_chars < self.max_steps as usize {
Some(CycleSearchResult::ProperList(self.num_steps())) self.pstr_chars += num_chars;
Some(CycleSearchResult::ProperList(self.num_steps()))
} else {
let offset = self.num_steps() + num_chars - self.max_steps as usize;
self.pstr_chars += offset;
Some(CycleSearchResult::PStrLocation(self.max_steps as usize, h, offset))
}
} }
(HeapCellValueTag::PStr, pstr_atom) => { (HeapCellValueTag::PStr, pstr_atom) => {
let pstr = PartialString::from(pstr_atom); let pstr = PartialString::from(pstr_atom);
let num_chars = pstr.as_str_from(offset).chars().count();
self.pstr_chars += pstr.as_str_from(0).chars().count() - 1; if self.max_steps == -1 || self.num_steps() + num_chars < self.max_steps as usize {
self.step(h+1) self.pstr_chars += num_chars - 1;
} self.step(h+1)
(HeapCellValueTag::PStrOffset, offset) => {
let pstr = cell_as_string!(heap[offset]);
let n = cell_as_fixnum!(heap[h+1]).get_num() as usize;
self.pstr_chars += pstr.as_str_from(n).chars().count();
if let HeapCellValueTag::PStr = heap[offset].get_tag() {
self.pstr_chars -= 1;
self.step(offset+1)
} else { } else {
debug_assert!(heap[offset].get_tag() == HeapCellValueTag::CStr); let offset = self.num_steps() + num_chars - self.max_steps as usize;
Some(CycleSearchResult::ProperList(self.num_steps())) self.pstr_chars += offset;
Some(CycleSearchResult::PStrLocation(self.max_steps as usize, h, offset))
} }
} }
_ => { _ => {
@@ -235,6 +260,18 @@ impl BrentAlgState {
) )
} }
fn add_pstr_chars_and_step(&mut self, heap: &[HeapCellValue], h: usize) -> Option<CycleSearchResult> {
read_heap_cell!(heap[h],
(HeapCellValueTag::PStrOffset, l) => {
let (pstr_loc, offset) = pstr_loc_and_offset(heap, l);
self.add_pstr_offset_chars(heap, pstr_loc, offset.get_num() as usize)
}
_ => {
self.add_pstr_offset_chars(heap, h, 0)
}
)
}
#[inline(always)] #[inline(always)]
fn cycle_step(&mut self, heap: &[HeapCellValue]) -> Option<CycleSearchResult> { fn cycle_step(&mut self, heap: &[HeapCellValue]) -> Option<CycleSearchResult> {
loop { loop {
@@ -388,7 +425,7 @@ impl BrentAlgState {
} }
if pstr_chars + 1 > max_steps { if pstr_chars + 1 > max_steps {
return CycleSearchResult::PStrLocation(max_steps, h_offset); return CycleSearchResult::PStrLocation(max_steps, h_offset, max_steps);
} }
h_offset+1 h_offset+1
@@ -444,9 +481,10 @@ impl BrentAlgState {
brent_st.power += 1; // advance a step. brent_st.power += 1; // advance a step.
brent_st.pstr_chars = pstr_chars; brent_st.pstr_chars = pstr_chars;
brent_st.max_steps = max_steps as i64;
loop { loop {
if brent_st.num_steps() >= max_steps { if brent_st.exhausted_max_steps() {
return brent_st.to_result(&heap); return brent_st.to_result(&heap);
} }
@@ -638,8 +676,25 @@ impl MachineState {
}; };
match search_result { match search_result {
CycleSearchResult::PStrLocation(steps, pstr_loc) => { CycleSearchResult::PStrLocation(steps, pstr_loc, offset) => {
self.finalize_skip_max_list(steps as i64, pstr_loc_as_cell!(pstr_loc)); let steps = if max_steps > - 1 {
std::cmp::min(max_steps, steps as i64)
} else {
steps as i64
};
let cell = if offset > 0 {
let h = self.heap.len();
self.heap.push(pstr_offset_as_cell!(pstr_loc));
self.heap.push(fixnum_as_cell!(Fixnum::build_with(offset as i64)));
pstr_loc_as_cell!(h)
} else {
pstr_loc_as_cell!(pstr_loc)
};
self.finalize_skip_max_list(steps, cell);
} }
CycleSearchResult::UntouchedList(n, l) => { CycleSearchResult::UntouchedList(n, l) => {
self.finalize_skip_max_list(n as i64, list_loc_as_cell!(l)); self.finalize_skip_max_list(n as i64, list_loc_as_cell!(l));