support comparison and unification of cyclic partial strings
This commit is contained in:
@@ -343,6 +343,13 @@ impl MachineState {
|
|||||||
(HeapCellValueTag::CStr, cstr_atom) => {
|
(HeapCellValueTag::CStr, cstr_atom) => {
|
||||||
self.fail = atom != 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;
|
self.fail = true;
|
||||||
}
|
}
|
||||||
@@ -367,12 +374,20 @@ impl MachineState {
|
|||||||
match compare_pstr_prefixes(&mut pstr_iter1, &mut pstr_iter2) {
|
match compare_pstr_prefixes(&mut pstr_iter1, &mut pstr_iter2) {
|
||||||
PStrCmpResult::Ordered(Ordering::Equal) => {}
|
PStrCmpResult::Ordered(Ordering::Equal) => {}
|
||||||
PStrCmpResult::Ordered(Ordering::Less) => {
|
PStrCmpResult::Ordered(Ordering::Less) => {
|
||||||
self.pdl.push(empty_list_as_cell!());
|
if pstr_iter2.focus.as_var().is_none() {
|
||||||
self.pdl.push(pstr_iter2.focus);
|
self.fail = true;
|
||||||
|
} else {
|
||||||
|
self.pdl.push(empty_list_as_cell!());
|
||||||
|
self.pdl.push(pstr_iter2.focus);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
PStrCmpResult::Ordered(Ordering::Greater) => {
|
PStrCmpResult::Ordered(Ordering::Greater) => {
|
||||||
self.pdl.push(empty_list_as_cell!());
|
if pstr_iter1.focus.as_var().is_none() {
|
||||||
self.pdl.push(pstr_iter1.focus);
|
self.fail = true;
|
||||||
|
} else {
|
||||||
|
self.pdl.push(empty_list_as_cell!());
|
||||||
|
self.pdl.push(pstr_iter1.focus);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
continuable @ PStrCmpResult::FirstIterContinuable(iteratee) |
|
continuable @ PStrCmpResult::FirstIterContinuable(iteratee) |
|
||||||
continuable @ PStrCmpResult::SecondIterContinuable(iteratee) => {
|
continuable @ PStrCmpResult::SecondIterContinuable(iteratee) => {
|
||||||
@@ -1014,12 +1029,20 @@ impl MachineState {
|
|||||||
match compare_pstr_prefixes(&mut pstr_iter1, &mut pstr_iter2) {
|
match compare_pstr_prefixes(&mut pstr_iter1, &mut pstr_iter2) {
|
||||||
PStrCmpResult::Ordered(Ordering::Equal) => {}
|
PStrCmpResult::Ordered(Ordering::Equal) => {}
|
||||||
PStrCmpResult::Ordered(Ordering::Less) => {
|
PStrCmpResult::Ordered(Ordering::Less) => {
|
||||||
self.pdl.push(empty_list_as_cell!());
|
if pstr_iter2.focus.as_var().is_none() {
|
||||||
self.pdl.push(pstr_iter2.focus);
|
self.fail = true;
|
||||||
|
} else {
|
||||||
|
self.pdl.push(empty_list_as_cell!());
|
||||||
|
self.pdl.push(pstr_iter2.focus);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
PStrCmpResult::Ordered(Ordering::Greater) => {
|
PStrCmpResult::Ordered(Ordering::Greater) => {
|
||||||
self.pdl.push(empty_list_as_cell!());
|
if pstr_iter1.focus.as_var().is_none() {
|
||||||
self.pdl.push(pstr_iter1.focus);
|
self.fail = true;
|
||||||
|
} else {
|
||||||
|
self.pdl.push(empty_list_as_cell!());
|
||||||
|
self.pdl.push(pstr_iter1.focus);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
continuable @ PStrCmpResult::FirstIterContinuable(iteratee) |
|
continuable @ PStrCmpResult::FirstIterContinuable(iteratee) |
|
||||||
continuable @ PStrCmpResult::SecondIterContinuable(iteratee) => {
|
continuable @ PStrCmpResult::SecondIterContinuable(iteratee) => {
|
||||||
|
|||||||
@@ -539,18 +539,33 @@ pub fn compare_pstr_prefixes<'a>(
|
|||||||
i2: &mut HeapPStrIter<'a>,
|
i2: &mut HeapPStrIter<'a>,
|
||||||
) -> PStrCmpResult {
|
) -> PStrCmpResult {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn consolidate_step(iter: &mut HeapPStrIter, step: &PStrIterStep) -> bool {
|
fn step(iter: &mut HeapPStrIter, hare: usize) -> Option<PStrIterStep> {
|
||||||
iter.focus = iter.heap[step.next_hare];
|
let result = iter.step(hare);
|
||||||
|
|
||||||
|
iter.focus = iter.heap[hare];
|
||||||
|
|
||||||
if iter.focus.is_string_terminator(iter.heap) {
|
if iter.focus.is_string_terminator(iter.heap) {
|
||||||
iter.focus = empty_list_as_cell!();
|
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);
|
#[inline(always)]
|
||||||
let mut r2 = i2.step(i2.brent_st.hare);
|
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 {
|
loop {
|
||||||
if let Some(step_1) = r1.as_mut() {
|
if let Some(step_1) = r1.as_mut() {
|
||||||
@@ -561,21 +576,14 @@ pub fn compare_pstr_prefixes<'a>(
|
|||||||
return PStrCmpResult::Ordered(c1.cmp(&c2));
|
return PStrCmpResult::Ordered(c1.cmp(&c2));
|
||||||
}
|
}
|
||||||
|
|
||||||
let c1_result = consolidate_step(i1, &step_1);
|
cycle_detection_step(i1, i2, &step_1);
|
||||||
let c2_result = consolidate_step(i2, &step_2);
|
let both_cyclic = cycle_detection_step(i2, i1, &step_2);
|
||||||
|
|
||||||
if c1_result {
|
r1 = step(i1, i1.brent_st.hare);
|
||||||
r1 = i1.step(i1.brent_st.hare);
|
r2 = step(i2, i2.brent_st.hare);
|
||||||
}
|
|
||||||
|
|
||||||
if c2_result {
|
if !both_cyclic {
|
||||||
r2 = i2.step(i2.brent_st.hare);
|
|
||||||
}
|
|
||||||
|
|
||||||
if c1_result && c2_result {
|
|
||||||
continue;
|
continue;
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(PStrIteratee::Char(_, c1), PStrIteratee::PStrSegment(f2, pstr_atom, n)) => {
|
(PStrIteratee::Char(_, c1), PStrIteratee::PStrSegment(f2, pstr_atom, n)) => {
|
||||||
@@ -591,36 +599,29 @@ pub fn compare_pstr_prefixes<'a>(
|
|||||||
if n1 < pstr_atom.len() {
|
if n1 < pstr_atom.len() {
|
||||||
step_2.iteratee = PStrIteratee::PStrSegment(f2, pstr_atom, n1);
|
step_2.iteratee = PStrIteratee::PStrSegment(f2, pstr_atom, n1);
|
||||||
|
|
||||||
if consolidate_step(i1, &step_1) {
|
let c1_result = cycle_detection_step(i1, i2, &step_1);
|
||||||
r1 = i1.step(step_1.next_hare);
|
r1 = step(i1, i1.brent_st.hare);
|
||||||
|
|
||||||
|
if !c1_result {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let c1_result = consolidate_step(i1, &step_1);
|
cycle_detection_step(i1, i2, &step_1);
|
||||||
let c2_result = consolidate_step(i2, &step_2);
|
let both_cyclic = cycle_detection_step(i2, i1, &step_2);
|
||||||
|
|
||||||
if c1_result {
|
r1 = step(i1, i1.brent_st.hare);
|
||||||
r1 = i1.step(i1.brent_st.hare);
|
r2 = step(i2, i2.brent_st.hare);
|
||||||
}
|
|
||||||
|
|
||||||
if c2_result {
|
if !both_cyclic {
|
||||||
r2 = i2.step(i2.brent_st.hare);
|
|
||||||
}
|
|
||||||
|
|
||||||
if c1_result && c2_result {
|
|
||||||
continue;
|
continue;
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if consolidate_step(i2, &step_2) {
|
let c2_result = cycle_detection_step(i2, i1, &step_2);
|
||||||
r2 = i2.step(step_2.next_hare);
|
r2 = step(i2, i2.brent_st.hare);
|
||||||
|
|
||||||
|
if !c2_result {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -637,54 +638,42 @@ pub fn compare_pstr_prefixes<'a>(
|
|||||||
if n1 < pstr_atom.len() {
|
if n1 < pstr_atom.len() {
|
||||||
step_1.iteratee = PStrIteratee::PStrSegment(f1, pstr_atom, n1);
|
step_1.iteratee = PStrIteratee::PStrSegment(f1, pstr_atom, n1);
|
||||||
|
|
||||||
if consolidate_step(i2, &step_2) {
|
let c2_result = cycle_detection_step(i2, i1, &step_2);
|
||||||
r2 = i2.step(step_2.next_hare);
|
r2 = step(i2, step_2.next_hare);
|
||||||
|
|
||||||
|
if !c2_result {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let c1_result = consolidate_step(i1, &step_1);
|
cycle_detection_step(i1, i2, &step_1);
|
||||||
let c2_result = consolidate_step(i2, &step_2);
|
let both_cyclic = cycle_detection_step(i2, i1, &step_2);
|
||||||
|
|
||||||
if c1_result {
|
r1 = step(i1, i1.brent_st.hare);
|
||||||
r1 = i1.step(i1.brent_st.hare);
|
r2 = step(i2, i2.brent_st.hare);
|
||||||
}
|
|
||||||
|
|
||||||
if c2_result {
|
if !both_cyclic {
|
||||||
r2 = i2.step(i2.brent_st.hare);
|
|
||||||
}
|
|
||||||
|
|
||||||
if c1_result && c2_result {
|
|
||||||
continue;
|
continue;
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if consolidate_step(i1, &step_1) {
|
let c1_result = cycle_detection_step(i1, i2, &step_1);
|
||||||
r1 = i1.step(step_1.next_hare);
|
r1 = step(i1, i1.brent_st.hare);
|
||||||
|
|
||||||
|
if !c1_result {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(PStrIteratee::PStrSegment(f1, pstr1_atom, n1),
|
(PStrIteratee::PStrSegment(f1, pstr1_atom, n1),
|
||||||
PStrIteratee::PStrSegment(f2, pstr2_atom, n2)) => {
|
PStrIteratee::PStrSegment(f2, pstr2_atom, n2)) => {
|
||||||
if pstr1_atom == pstr2_atom && n1 == n2 {
|
if pstr1_atom == pstr2_atom && n1 == n2 {
|
||||||
let c_result1 = consolidate_step(i1, &step_1);
|
cycle_detection_step(i1, i2, &step_1);
|
||||||
let c_result2 = consolidate_step(i2, &step_2);
|
let both_cyclic = cycle_detection_step(i2, i1, &step_2);
|
||||||
|
|
||||||
if c_result1 {
|
r1 = step(i1, i1.brent_st.hare);
|
||||||
r1 = i1.step(step_1.next_hare);
|
r2 = step(i2, i2.brent_st.hare);
|
||||||
}
|
|
||||||
|
|
||||||
if c_result2 {
|
if !both_cyclic {
|
||||||
r2 = i2.step(step_2.next_hare);
|
|
||||||
}
|
|
||||||
|
|
||||||
if c_result1 && c_result2 {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -699,41 +688,32 @@ pub fn compare_pstr_prefixes<'a>(
|
|||||||
|
|
||||||
match str1.len().cmp(&str2.len()) {
|
match str1.len().cmp(&str2.len()) {
|
||||||
Ordering::Equal if str1 == str2 => {
|
Ordering::Equal if str1 == str2 => {
|
||||||
let c_result1 = consolidate_step(i1, &step_1);
|
cycle_detection_step(i1, i2, &step_1);
|
||||||
let c_result2 = consolidate_step(i2, &step_2);
|
let both_cyclic = cycle_detection_step(i2, i1, &step_2);
|
||||||
|
|
||||||
if c_result1 {
|
r1 = step(i1, i1.brent_st.hare);
|
||||||
r1 = i1.step(step_1.next_hare);
|
r2 = step(i2, i2.brent_st.hare);
|
||||||
}
|
|
||||||
|
|
||||||
if c_result2 {
|
if !both_cyclic {
|
||||||
r2 = i2.step(step_2.next_hare);
|
|
||||||
}
|
|
||||||
|
|
||||||
if c_result1 && c_result2 {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
Ordering::Less if str2.starts_with(str1) => {
|
Ordering::Less if str2.starts_with(str1) => {
|
||||||
step_2.iteratee = PStrIteratee::PStrSegment(f2, pstr2_atom, n2 + str1.len());
|
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) {
|
if !c1_result {
|
||||||
r1 = i1.step(step_1.next_hare);
|
|
||||||
continue;
|
continue;
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ordering::Greater if str1.starts_with(str2) => {
|
Ordering::Greater if str1.starts_with(str2) => {
|
||||||
step_1.iteratee = PStrIteratee::PStrSegment(f1, pstr1_atom, n1 + str2.len());
|
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) {
|
if !c2_result {
|
||||||
r2 = i2.step(step_2.next_hare);
|
|
||||||
continue;
|
continue;
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -757,22 +737,33 @@ pub fn compare_pstr_prefixes<'a>(
|
|||||||
// and thus matched by the compare_pstr_prefixes loop previously,
|
// and thus matched by the compare_pstr_prefixes loop previously,
|
||||||
// so here it suffices to check if they are both continuable.
|
// so here it suffices to check if they are both continuable.
|
||||||
|
|
||||||
if i1.focus == i2.focus {
|
let r1_at_end = r1.is_none();
|
||||||
PStrCmpResult::Ordered(Ordering::Equal)
|
let r2_at_end = r2.is_none();
|
||||||
} 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
PStrCmpResult::FirstIterContinuable(r1.unwrap().iteratee)
|
if r1_at_end && r2_at_end {
|
||||||
} else if i2.is_continuable() {
|
if i1.focus == i2.focus {
|
||||||
PStrCmpResult::SecondIterContinuable(r2.unwrap().iteratee)
|
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 {
|
} 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)]
|
#[inline(always)]
|
||||||
pub fn step(&mut self, hare: usize) -> Option<CycleSearchResult> {
|
pub fn step(&mut self, hare: usize) -> Option<CycleSearchResult> {
|
||||||
self.hare = hare;
|
self.hare = hare;
|
||||||
@@ -120,10 +129,8 @@ impl BrentAlgState {
|
|||||||
|
|
||||||
if self.tortoise == self.hare {
|
if self.tortoise == self.hare {
|
||||||
return Some(CycleSearchResult::NotList);
|
return Some(CycleSearchResult::NotList);
|
||||||
} else if self.lam == self.power {
|
} else {
|
||||||
self.tortoise = self.hare;
|
self.teleport_tortoise();
|
||||||
self.power <<= 1;
|
|
||||||
self.lam = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
|
|||||||
Reference in New Issue
Block a user