support comparison and unification of cyclic partial strings
This commit is contained in:
@@ -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) => {
|
||||
|
||||
@@ -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<PStrIterStep> {
|
||||
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
|
||||
}
|
||||
|
||||
let mut r1 = i1.step(i1.brent_st.hare);
|
||||
let mut r2 = i2.step(i2.brent_st.hare);
|
||||
#[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 = 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);
|
||||
}
|
||||
r1 = step(i1, i1.brent_st.hare);
|
||||
r2 = step(i2, i2.brent_st.hare);
|
||||
|
||||
if c2_result {
|
||||
r2 = i2.step(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);
|
||||
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);
|
||||
}
|
||||
r1 = step(i1, i1.brent_st.hare);
|
||||
r2 = step(i2, i2.brent_st.hare);
|
||||
|
||||
if c2_result {
|
||||
r2 = i2.step(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);
|
||||
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);
|
||||
}
|
||||
r1 = step(i1, i1.brent_st.hare);
|
||||
r2 = step(i2, i2.brent_st.hare);
|
||||
|
||||
if c2_result {
|
||||
r2 = i2.step(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);
|
||||
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);
|
||||
}
|
||||
r1 = step(i1, i1.brent_st.hare);
|
||||
r2 = step(i2, i2.brent_st.hare);
|
||||
|
||||
if c_result2 {
|
||||
r2 = i2.step(step_2.next_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);
|
||||
}
|
||||
r1 = step(i1, i1.brent_st.hare);
|
||||
r2 = step(i2, i2.brent_st.hare);
|
||||
|
||||
if c_result2 {
|
||||
r2 = i2.step(step_2.next_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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<CycleSearchResult> {
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user