From: Mark Thom Date: Thu, 18 Nov 2021 06:29:23 +0000 (-0700) Subject: support comparison and unification of cyclic partial strings X-Git-Tag: v0.9.0^2~130 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=b24e7cce38991a79f517f87f923c42495a1a3b79;p=scryer-prolog.git support comparison and unification of cyclic partial strings --- diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index 89dd4269..1caa8a96 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -343,6 +343,13 @@ impl MachineState { (HeapCellValueTag::CStr, cstr_atom) => { self.fail = atom != cstr_atom; } + (HeapCellValueTag::Str | HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => { + self.unify_partial_string(atom_as_cstr_cell!(atom), value); + + if !self.pdl.is_empty() { + self.unify(); + } + } _ => { self.fail = true; } @@ -367,12 +374,20 @@ impl MachineState { match compare_pstr_prefixes(&mut pstr_iter1, &mut pstr_iter2) { PStrCmpResult::Ordered(Ordering::Equal) => {} PStrCmpResult::Ordered(Ordering::Less) => { - self.pdl.push(empty_list_as_cell!()); - self.pdl.push(pstr_iter2.focus); + if pstr_iter2.focus.as_var().is_none() { + self.fail = true; + } else { + self.pdl.push(empty_list_as_cell!()); + self.pdl.push(pstr_iter2.focus); + } } PStrCmpResult::Ordered(Ordering::Greater) => { - self.pdl.push(empty_list_as_cell!()); - self.pdl.push(pstr_iter1.focus); + if pstr_iter1.focus.as_var().is_none() { + self.fail = true; + } else { + self.pdl.push(empty_list_as_cell!()); + self.pdl.push(pstr_iter1.focus); + } } continuable @ PStrCmpResult::FirstIterContinuable(iteratee) | continuable @ PStrCmpResult::SecondIterContinuable(iteratee) => { @@ -1014,12 +1029,20 @@ impl MachineState { match compare_pstr_prefixes(&mut pstr_iter1, &mut pstr_iter2) { PStrCmpResult::Ordered(Ordering::Equal) => {} PStrCmpResult::Ordered(Ordering::Less) => { - self.pdl.push(empty_list_as_cell!()); - self.pdl.push(pstr_iter2.focus); + if pstr_iter2.focus.as_var().is_none() { + self.fail = true; + } else { + self.pdl.push(empty_list_as_cell!()); + self.pdl.push(pstr_iter2.focus); + } } PStrCmpResult::Ordered(Ordering::Greater) => { - self.pdl.push(empty_list_as_cell!()); - self.pdl.push(pstr_iter1.focus); + if pstr_iter1.focus.as_var().is_none() { + self.fail = true; + } else { + self.pdl.push(empty_list_as_cell!()); + self.pdl.push(pstr_iter1.focus); + } } continuable @ PStrCmpResult::FirstIterContinuable(iteratee) | continuable @ PStrCmpResult::SecondIterContinuable(iteratee) => { diff --git a/src/machine/partial_string.rs b/src/machine/partial_string.rs index da32db4f..87256d04 100644 --- a/src/machine/partial_string.rs +++ b/src/machine/partial_string.rs @@ -539,18 +539,33 @@ pub fn compare_pstr_prefixes<'a>( i2: &mut HeapPStrIter<'a>, ) -> PStrCmpResult { #[inline(always)] - fn consolidate_step(iter: &mut HeapPStrIter, step: &PStrIterStep) -> bool { - iter.focus = iter.heap[step.next_hare]; + fn step(iter: &mut HeapPStrIter, hare: usize) -> Option { + let result = iter.step(hare); + + iter.focus = iter.heap[hare]; if iter.focus.is_string_terminator(iter.heap) { iter.focus = empty_list_as_cell!(); } - !iter.brent_st.step(step.next_hare).is_some() + result + } + + #[inline(always)] + fn cycle_detection_step(i1: &mut HeapPStrIter, i2: &HeapPStrIter, step: &PStrIterStep) -> bool { + if i1.cycle_detected() { + i1.brent_st.hare = step.next_hare; + i2.cycle_detected() + } else if i1.brent_st.step(step.next_hare).is_some() { + i1.stepper = HeapPStrIter::post_cycle_discovery_stepper; + i2.cycle_detected() + } else { + false + } } - let mut r1 = i1.step(i1.brent_st.hare); - let mut r2 = i2.step(i2.brent_st.hare); + let mut r1 = step(i1, i1.brent_st.hare); + let mut r2 = step(i2, i2.brent_st.hare); loop { if let Some(step_1) = r1.as_mut() { @@ -561,21 +576,14 @@ pub fn compare_pstr_prefixes<'a>( return PStrCmpResult::Ordered(c1.cmp(&c2)); } - let c1_result = consolidate_step(i1, &step_1); - let c2_result = consolidate_step(i2, &step_2); + cycle_detection_step(i1, i2, &step_1); + let both_cyclic = cycle_detection_step(i2, i1, &step_2); - if c1_result { - r1 = i1.step(i1.brent_st.hare); - } - - if c2_result { - r2 = i2.step(i2.brent_st.hare); - } + r1 = step(i1, i1.brent_st.hare); + r2 = step(i2, i2.brent_st.hare); - if c1_result && c2_result { + if !both_cyclic { continue; - } else { - break; } } (PStrIteratee::Char(_, c1), PStrIteratee::PStrSegment(f2, pstr_atom, n)) => { @@ -591,36 +599,29 @@ pub fn compare_pstr_prefixes<'a>( if n1 < pstr_atom.len() { step_2.iteratee = PStrIteratee::PStrSegment(f2, pstr_atom, n1); - if consolidate_step(i1, &step_1) { - r1 = i1.step(step_1.next_hare); + let c1_result = cycle_detection_step(i1, i2, &step_1); + r1 = step(i1, i1.brent_st.hare); + + if !c1_result { continue; - } else { - break; } } else { - let c1_result = consolidate_step(i1, &step_1); - let c2_result = consolidate_step(i2, &step_2); - - if c1_result { - r1 = i1.step(i1.brent_st.hare); - } + cycle_detection_step(i1, i2, &step_1); + let both_cyclic = cycle_detection_step(i2, i1, &step_2); - if c2_result { - r2 = i2.step(i2.brent_st.hare); - } + r1 = step(i1, i1.brent_st.hare); + r2 = step(i2, i2.brent_st.hare); - if c1_result && c2_result { + if !both_cyclic { continue; - } else { - break; } } } else { - if consolidate_step(i2, &step_2) { - r2 = i2.step(step_2.next_hare); + let c2_result = cycle_detection_step(i2, i1, &step_2); + r2 = step(i2, i2.brent_st.hare); + + if !c2_result { continue; - } else { - break; } } } @@ -637,54 +638,42 @@ pub fn compare_pstr_prefixes<'a>( if n1 < pstr_atom.len() { step_1.iteratee = PStrIteratee::PStrSegment(f1, pstr_atom, n1); - if consolidate_step(i2, &step_2) { - r2 = i2.step(step_2.next_hare); + let c2_result = cycle_detection_step(i2, i1, &step_2); + r2 = step(i2, step_2.next_hare); + + if !c2_result { continue; - } else { - break; } } else { - let c1_result = consolidate_step(i1, &step_1); - let c2_result = consolidate_step(i2, &step_2); - - if c1_result { - r1 = i1.step(i1.brent_st.hare); - } + cycle_detection_step(i1, i2, &step_1); + let both_cyclic = cycle_detection_step(i2, i1, &step_2); - if c2_result { - r2 = i2.step(i2.brent_st.hare); - } + r1 = step(i1, i1.brent_st.hare); + r2 = step(i2, i2.brent_st.hare); - if c1_result && c2_result { + if !both_cyclic { continue; - } else { - break; } } } else { - if consolidate_step(i1, &step_1) { - r1 = i1.step(step_1.next_hare); + let c1_result = cycle_detection_step(i1, i2, &step_1); + r1 = step(i1, i1.brent_st.hare); + + if !c1_result { continue; - } else { - break; } } } (PStrIteratee::PStrSegment(f1, pstr1_atom, n1), PStrIteratee::PStrSegment(f2, pstr2_atom, n2)) => { if pstr1_atom == pstr2_atom && n1 == n2 { - let c_result1 = consolidate_step(i1, &step_1); - let c_result2 = consolidate_step(i2, &step_2); - - if c_result1 { - r1 = i1.step(step_1.next_hare); - } + cycle_detection_step(i1, i2, &step_1); + let both_cyclic = cycle_detection_step(i2, i1, &step_2); - if c_result2 { - r2 = i2.step(step_2.next_hare); - } + r1 = step(i1, i1.brent_st.hare); + r2 = step(i2, i2.brent_st.hare); - if c_result1 && c_result2 { + if !both_cyclic { continue; } @@ -699,41 +688,32 @@ pub fn compare_pstr_prefixes<'a>( match str1.len().cmp(&str2.len()) { Ordering::Equal if str1 == str2 => { - let c_result1 = consolidate_step(i1, &step_1); - let c_result2 = consolidate_step(i2, &step_2); + cycle_detection_step(i1, i2, &step_1); + let both_cyclic = cycle_detection_step(i2, i1, &step_2); - if c_result1 { - r1 = i1.step(step_1.next_hare); - } - - if c_result2 { - r2 = i2.step(step_2.next_hare); - } + r1 = step(i1, i1.brent_st.hare); + r2 = step(i2, i2.brent_st.hare); - if c_result1 && c_result2 { + if !both_cyclic { continue; } - - break; } Ordering::Less if str2.starts_with(str1) => { step_2.iteratee = PStrIteratee::PStrSegment(f2, pstr2_atom, n2 + str1.len()); + let c1_result = cycle_detection_step(i1, i2, &step_1); + r1 = step(i1, i1.brent_st.hare); - if consolidate_step(i1, &step_1) { - r1 = i1.step(step_1.next_hare); + if !c1_result { continue; - } else { - break; } } Ordering::Greater if str1.starts_with(str2) => { step_1.iteratee = PStrIteratee::PStrSegment(f1, pstr1_atom, n1 + str2.len()); + let c2_result = cycle_detection_step(i2, i1, &step_2); + r2 = step(i2, i2.brent_st.hare); - if consolidate_step(i2, &step_2) { - r2 = i2.step(step_2.next_hare); + if !c2_result { continue; - } else { - break; } } _ => { @@ -757,22 +737,33 @@ pub fn compare_pstr_prefixes<'a>( // and thus matched by the compare_pstr_prefixes loop previously, // so here it suffices to check if they are both continuable. - if i1.focus == i2.focus { - PStrCmpResult::Ordered(Ordering::Equal) - } else if i1.focus == empty_list_as_cell!() { - PStrCmpResult::Ordered(Ordering::Less) - } else if i2.focus == empty_list_as_cell!() { - PStrCmpResult::Ordered(Ordering::Greater) - } else if i1.is_continuable() { - if i2.is_continuable() { - return PStrCmpResult::Ordered(Ordering::Equal); - } + let r1_at_end = r1.is_none(); + let r2_at_end = r2.is_none(); - PStrCmpResult::FirstIterContinuable(r1.unwrap().iteratee) - } else if i2.is_continuable() { - PStrCmpResult::SecondIterContinuable(r2.unwrap().iteratee) + if r1_at_end && r2_at_end { + if i1.focus == i2.focus { + PStrCmpResult::Ordered(Ordering::Equal) + } else { + PStrCmpResult::Unordered + } + } else if r1_at_end { + if i1.focus == empty_list_as_cell!() { + PStrCmpResult::Ordered(Ordering::Less) + } else { + PStrCmpResult::SecondIterContinuable(r2.unwrap().iteratee) + } + } else if r2_at_end { + if i2.focus == empty_list_as_cell!() { + PStrCmpResult::Ordered(Ordering::Greater) + } else { + PStrCmpResult::FirstIterContinuable(r1.unwrap().iteratee) + } } else { - PStrCmpResult::Unordered + if i1.is_continuable() && i2.is_continuable() { + PStrCmpResult::Ordered(Ordering::Equal) + } else { + PStrCmpResult::Unordered + } } } diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 7b85f2c4..dd385801 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -113,6 +113,15 @@ impl BrentAlgState { } } + #[inline(always)] + pub fn teleport_tortoise(&mut self) { + if self.lam == self.power { + self.tortoise = self.hare; + self.power <<= 1; + self.lam = 0; + } + } + #[inline(always)] pub fn step(&mut self, hare: usize) -> Option { self.hare = hare; @@ -120,10 +129,8 @@ impl BrentAlgState { if self.tortoise == self.hare { return Some(CycleSearchResult::NotList); - } else if self.lam == self.power { - self.tortoise = self.hare; - self.power <<= 1; - self.lam = 0; + } else { + self.teleport_tortoise(); } None