pub(crate) use crate::machine::gc::{IteratorUMP, StacklessPreOrderHeapIter}; use crate::machine::heap::*; use crate::atom_table::*; use crate::types::*; use modular_bitfield::prelude::*; use std::ops::Deref; use std::vec::Vec; #[inline] fn forward_if_referent_marked(heap: &mut [HeapCellValue], h: usize) { read_heap_cell!(heap[h], (HeapCellValueTag::Str | HeapCellValueTag::Lis | HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::PStrLoc, vh) => { if heap[vh].get_mark_bit() { heap[h].set_forwarding_bit(true); } } _ => {} ) } #[bitfield] #[repr(u64)] #[derive(Clone, Copy, Debug)] pub struct IterStackLoc { value: B63, m: bool, } impl IterStackLoc { #[inline] pub fn iterable_heap_loc(h: usize) -> Self { IterStackLoc::new().with_m(false).with_value(h as u64) } #[inline] pub fn mark_heap_loc(h: usize) -> Self { IterStackLoc::new().with_m(true).with_value(h as u64) } } #[derive(Debug)] pub struct StackfulPreOrderHeapIter<'a> { pub heap: &'a mut Vec, stack: Vec, h: usize, } impl<'a> Drop for StackfulPreOrderHeapIter<'a> { fn drop(&mut self) { while let Some(h) = self.stack.pop() { let h = h.value() as usize; self.heap[h].set_forwarding_bit(false); self.heap[h].set_mark_bit(false); } self.heap.pop(); } } impl<'a> StackfulPreOrderHeapIter<'a> { #[inline] fn new(heap: &'a mut Vec, cell: HeapCellValue) -> Self { let h = heap.len(); heap.push(cell); Self { heap, h, stack: vec![IterStackLoc::iterable_heap_loc(h)], } } #[inline] pub fn push_stack(&mut self, h: usize) { self.stack.push(IterStackLoc::iterable_heap_loc(h)); } #[inline] pub fn stack_last(&self) -> Option { for h in self.stack.iter().rev() { let is_readable_marked = h.m(); let h = h.value() as usize; let cell = self.heap[h]; if cell.get_forwarding_bit() == Some(true) { return Some(h); } else if cell.get_mark_bit() && !is_readable_marked { continue; } return Some(h); } None } #[inline] pub fn stack_is_empty(&self) -> bool { self.stack.is_empty() } #[inline] pub fn focus(&self) -> usize { self.h } #[inline] pub fn pop_stack(&mut self) -> Option { while let Some(h) = self.stack.pop() { let is_readable_marked = h.m(); let h = h.value() as usize; self.h = h; let cell = &mut self.heap[h]; if cell.get_forwarding_bit() == Some(true) { cell.set_forwarding_bit(false); } else if cell.get_mark_bit() && !is_readable_marked { cell.set_mark_bit(false); continue; } return Some(*cell); } None } fn push_if_unmarked(&mut self, h: usize) { if !self.heap[h].get_mark_bit() { self.heap[h].set_mark_bit(true); self.stack.push(IterStackLoc::iterable_heap_loc(h)); } } fn follow(&mut self) -> Option { while let Some(h) = self.stack.pop() { let is_readable_marked = h.m(); let h = h.value() as usize; self.h = h; let cell = &mut self.heap[h]; if cell.get_forwarding_bit() == Some(true) { let copy = *cell; cell.set_forwarding_bit(false); return Some(copy); } else if cell.get_mark_bit() && !is_readable_marked { cell.set_mark_bit(false); continue; } read_heap_cell!(*cell, (HeapCellValueTag::Str, vh) => { self.stack.push(IterStackLoc::iterable_heap_loc(vh)); } (HeapCellValueTag::Lis, vh) => { self.push_if_unmarked(vh); self.stack.push(IterStackLoc::iterable_heap_loc(vh + 1)); forward_if_referent_marked(&mut self.heap, vh + 1); self.stack.push(IterStackLoc::mark_heap_loc(vh)); forward_if_referent_marked(&mut self.heap, vh); return Some(self.heap[h]); } (HeapCellValueTag::AttrVar | HeapCellValueTag::PStrLoc | HeapCellValueTag::Var, vh) => { self.push_if_unmarked(h); self.stack.push(IterStackLoc::iterable_heap_loc(vh)); forward_if_referent_marked(&mut self.heap, vh); } (HeapCellValueTag::PStrOffset, offset) => { self.push_if_unmarked(offset); self.stack.push(IterStackLoc::iterable_heap_loc(h+1)); return Some(self.heap[h]); } (HeapCellValueTag::PStr) => { self.push_if_unmarked(h); forward_if_referent_marked(&mut self.heap, h+1); self.stack.push(IterStackLoc::iterable_heap_loc(h+1)); return Some(self.heap[h]); } (HeapCellValueTag::Atom, (_name, arity)) => { if arity > 0 { self.push_if_unmarked(h); } for h in (h + 1 .. h + arity + 1).rev() { forward_if_referent_marked(&mut self.heap, h); self.stack.push(IterStackLoc::iterable_heap_loc(h)); } return Some(self.heap[h]); } _ => { return Some(*cell); } ) } None } } impl<'a> Iterator for StackfulPreOrderHeapIter<'a> { type Item = HeapCellValue; #[inline] fn next(&mut self) -> Option { self.follow() } } #[inline(always)] pub(crate) fn stackless_preorder_iter( heap: &mut Vec, cell: HeapCellValue, ) -> StacklessPreOrderHeapIter { StacklessPreOrderHeapIter::new(heap, cell) } #[inline(always)] pub(crate) fn stackful_preorder_iter( heap: &mut Vec, cell: HeapCellValue, ) -> StackfulPreOrderHeapIter { StackfulPreOrderHeapIter::new(heap, cell) } #[derive(Debug)] pub(crate) struct PostOrderIterator> { base_iter: Iter, base_iter_valid: bool, parent_stack: Vec<(usize, HeapCellValue)>, // number of children, parent node. } impl> Deref for PostOrderIterator { type Target = Iter; fn deref(&self) -> &Self::Target { &self.base_iter } } impl> PostOrderIterator { pub(crate) fn new(base_iter: Iter) -> Self { PostOrderIterator { base_iter, base_iter_valid: true, parent_stack: vec![], } } } impl> Iterator for PostOrderIterator { type Item = HeapCellValue; fn next(&mut self) -> Option { loop { if let Some((child_count, node)) = self.parent_stack.pop() { if child_count == 0 { return Some(node); } self.parent_stack.push((child_count - 1, node)); } if self.base_iter_valid { if let Some(item) = self.base_iter.next() { read_heap_cell!(item, (HeapCellValueTag::Atom, (_name, arity)) => { self.parent_stack.push((arity, item)); } (HeapCellValueTag::Lis) => { self.parent_stack.push((2, item)); } (HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => { self.parent_stack.push((1, item)); } _ => { return Some(item); } ); continue; } else { self.base_iter_valid = false; } } if self.parent_stack.is_empty() { return None; } } } } pub(crate) type LeftistPostOrderHeapIter<'a> = PostOrderIterator>; impl<'a> LeftistPostOrderHeapIter<'a> { #[inline] pub fn pop_stack(&mut self) { if let Some((child_count, _)) = self.parent_stack.last() { for _ in 0 .. *child_count { self.base_iter.pop_stack(); } self.parent_stack.pop(); } } #[inline] pub fn parent_stack_len(&self) -> usize { self.parent_stack.len() } } #[inline] pub(crate) fn stackful_post_order_iter<'a>( heap: &'a mut Heap, cell: HeapCellValue, ) -> LeftistPostOrderHeapIter<'a> { PostOrderIterator::new(StackfulPreOrderHeapIter::new(heap, cell)) } pub(crate) type RightistPostOrderHeapIter<'a> = PostOrderIterator>; #[inline] pub(crate) fn stackless_post_order_iter<'a>( heap: &'a mut Heap, cell: HeapCellValue, ) -> RightistPostOrderHeapIter<'a> { PostOrderIterator::new(stackless_preorder_iter(heap, cell)) } #[cfg(test)] mod tests { use super::*; use crate::machine::mock_wam::*; #[test] fn heap_stackless_iter_tests() { let mut wam = MockWAM::new(); let f_atom = atom!("f"); let a_atom = atom!("a"); let b_atom = atom!("b"); wam.machine_st .heap .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, str_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 2) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom, 0) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom, 0) ); assert_eq!(iter.next(), None); } all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.clear(); wam.machine_st.heap.extend(functor!( f_atom, [ atom(a_atom), atom(b_atom), atom(a_atom), cell(str_loc_as_cell!(0)) ] )); for _ in 0..20 { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, str_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 4) ); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!(iter.next(), None); } all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.clear(); wam.machine_st.heap.push(str_loc_as_cell!(1)); wam.machine_st.heap.extend(functor!( f_atom, [ atom(a_atom), atom(b_atom), atom(a_atom), cell(str_loc_as_cell!(1)) ] )); for _ in 0..200000 { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 4) ); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(1)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!(iter.next(), None); } all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.clear(); { wam.machine_st.heap.push(heap_loc_as_cell!(0)); let mut iter = stackless_preorder_iter( &mut wam.machine_st.heap, heap_loc_as_cell!(0), ); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(0)); assert_eq!(iter.next(), None); } all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.clear(); // term is: [a, b] wam.machine_st.heap.push(list_loc_as_cell!(1)); wam.machine_st.heap.push(atom_as_cell!(a_atom)); wam.machine_st.heap.push(list_loc_as_cell!(3)); wam.machine_st.heap.push(atom_as_cell!(b_atom)); wam.machine_st.heap.push(empty_list_as_cell!()); { let mut iter = stackless_preorder_iter( &mut wam.machine_st.heap, heap_loc_as_cell!(0), ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(1) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), empty_list_as_cell!() ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!(iter.next(), None); } all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.pop(); // now make the list cyclic. wam.machine_st.heap.push(heap_loc_as_cell!(0)); { let mut iter = stackless_preorder_iter( &mut wam.machine_st.heap, heap_loc_as_cell!(0), ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(1) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(0) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!(iter.next(), None); } wam.machine_st.heap.clear(); // first a 'dangling' partial string, later modified to be a two-part complete string, // then a three-part cyclic string involving an uncompacted list of chars. let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "abc ", &mut wam.machine_st.atom_tbl); let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(1), ); assert_eq!(iter.next(), None); } assert_eq!(wam.machine_st.heap[0], pstr_cell); assert_eq!(wam.machine_st.heap[1], heap_loc_as_cell!(1)); wam.machine_st.heap.pop(); wam.machine_st.heap.push(pstr_loc_as_cell!(2)); let pstr_second_var_cell = put_partial_string( &mut wam.machine_st.heap, "def", &mut wam.machine_st.atom_tbl, ); let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(3), ); assert_eq!(iter.next(), None); } assert_eq!(wam.machine_st.heap[0], pstr_cell); assert_eq!(wam.machine_st.heap[1], pstr_loc_as_cell!(2)); assert_eq!(wam.machine_st.heap[2], pstr_second_cell); assert_eq!(wam.machine_st.heap[3], heap_loc_as_cell!(3)); wam.machine_st.heap.pop(); wam.machine_st.heap.push(pstr_loc_as_cell!(4)); wam.machine_st.heap.push(pstr_offset_as_cell!(0)); wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(2))); { let mut iter = stackless_preorder_iter( &mut wam.machine_st.heap, pstr_loc_as_cell!(4), ); let pstr_offset_cell = pstr_offset_as_cell!(0); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); assert_eq!(iter.next(), None); } assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_loc_as_cell!(2)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_second_cell); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_loc_as_cell!(4)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_offset_as_cell!(0)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), fixnum_as_cell!(Fixnum::build_with(2))); wam.machine_st.heap.truncate(4); wam.machine_st.heap.pop(); wam.machine_st.heap.push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1)); wam.machine_st.heap.push(pstr_offset_as_cell!(0)); wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0i64))); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); let pstr_offset_cell = pstr_offset_as_cell!(0); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell); assert_eq!(iter.next(), None); } all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.pop(); wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(1i64))); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0)); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0)); assert_eq!(iter.next(), None); assert_eq!(iter.heap[4], pstr_offset_as_cell!(0)); assert_eq!(iter.heap[5], fixnum_as_cell!(Fixnum::build_with(1i64))); } all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.clear(); let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]); wam.machine_st.heap.push(list_loc_as_cell!(1)); wam.machine_st.heap.push(str_loc_as_cell!(5)); wam.machine_st.heap.push(list_loc_as_cell!(3)); wam.machine_st.heap.push(str_loc_as_cell!(5)); wam.machine_st.heap.push(empty_list_as_cell!()); wam.machine_st.heap.extend(functor); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(1) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), empty_list_as_cell!() ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!(iter.next(), None); } all_cells_unmarked(&wam.machine_st.heap); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(1) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), empty_list_as_cell!() ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); // drop the iterator before the iteration is complete to test // that modified heap cells are restored to their // pre-traversal state by the stackless iterator's Drop // instance. } all_cells_unmarked(&wam.machine_st.heap); assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1)); assert_eq!(wam.machine_st.heap[1], str_loc_as_cell!(5)); assert_eq!(wam.machine_st.heap[2], list_loc_as_cell!(3)); assert_eq!(wam.machine_st.heap[3], str_loc_as_cell!(5)); assert_eq!(wam.machine_st.heap[4], empty_list_as_cell!()); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(1) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), empty_list_as_cell!() ); // drop the iterator before the iteration is complete to test // that modified heap cells are restored to their // pre-traversal state by the stackless iterator's Drop // instance. } all_cells_unmarked(&wam.machine_st.heap); assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1)); assert_eq!(wam.machine_st.heap[1], str_loc_as_cell!(5)); assert_eq!(wam.machine_st.heap[2], list_loc_as_cell!(3)); assert_eq!(wam.machine_st.heap[3], str_loc_as_cell!(5)); assert_eq!(wam.machine_st.heap[4], empty_list_as_cell!()); wam.machine_st.heap[4] = list_loc_as_cell!(1); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(1) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(1), ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!(iter.next(), None); } all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.clear(); wam.machine_st.heap.push(heap_loc_as_cell!(1)); wam.machine_st.heap.push(heap_loc_as_cell!(2)); wam.machine_st.heap.push(heap_loc_as_cell!(3)); wam.machine_st.heap.push(heap_loc_as_cell!(3)); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); assert_eq!(iter.next().unwrap(), heap_loc_as_cell!(3)); assert_eq!(iter.next(), None); } all_cells_unmarked(&wam.machine_st.heap); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), heap_loc_as_cell!(1)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(2)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(3)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), heap_loc_as_cell!(3)); wam.machine_st.heap.clear(); // print L = [L|L]. wam.machine_st.heap.push(list_loc_as_cell!(1)); wam.machine_st.heap.push(list_loc_as_cell!(1)); wam.machine_st.heap.push(list_loc_as_cell!(1)); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(1) ); assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1)); // this is what happens! this next line! We would like it not to happen though. assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1)); assert_eq!(iter.next(), None); } all_cells_unmarked(&wam.machine_st.heap); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(1)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), list_loc_as_cell!(1)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), list_loc_as_cell!(1)); wam.machine_st.heap.clear(); // term is [X,f(Y),Z]. wam.machine_st.heap.push(list_loc_as_cell!(1)); wam.machine_st.heap.push(heap_loc_as_cell!(1)); wam.machine_st.heap.push(heap_loc_as_cell!(3)); // 2 wam.machine_st.heap.push(list_loc_as_cell!(4)); // 3 wam.machine_st.heap.push(str_loc_as_cell!(6)); // 4 wam.machine_st.heap.push(heap_loc_as_cell!(8)); wam.machine_st.heap.push(atom_as_cell!(f_atom, 1)); // 6 wam.machine_st.heap.push(heap_loc_as_cell!(11)); // 7 wam.machine_st.heap.push(list_loc_as_cell!(9)); wam.machine_st.heap.push(heap_loc_as_cell!(9)); wam.machine_st.heap.push(empty_list_as_cell!()); wam.machine_st.heap.push(attr_var_as_cell!(11)); // linked from 7. wam.machine_st.heap.push(heap_loc_as_cell!(12)); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(4) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(9) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), empty_list_as_cell!() ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(9) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 1) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), attr_var_as_cell!(11) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(1) ); assert_eq!(iter.next(), None); } // now populate the attributes list. the iteration must not change. let clpz_atom = atom!("clpz"); let p_atom = atom!("p"); wam.machine_st.heap.pop(); wam.machine_st.heap.push(heap_loc_as_cell!(13)); // 12 wam.machine_st.heap.push(list_loc_as_cell!(14)); // 13 wam.machine_st.heap.push(str_loc_as_cell!(16)); // 14 wam.machine_st.heap.push(heap_loc_as_cell!(19)); // 15 wam.machine_st.heap.push(atom_as_cell!(clpz_atom, 2)); // 16 wam.machine_st.heap.push(atom_as_cell!(a_atom)); // 17 wam.machine_st.heap.push(atom_as_cell!(b_atom)); // 18 wam.machine_st.heap.push(list_loc_as_cell!(20)); // 19 wam.machine_st.heap.push(str_loc_as_cell!(22)); // 20 wam.machine_st.heap.push(empty_list_as_cell!()); // 21 wam.machine_st.heap.push(atom_as_cell!(p_atom, 1)); // 22 wam.machine_st.heap.push(heap_loc_as_cell!(23)); // 23 { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(4) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(9) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), empty_list_as_cell!() ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(9) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 1) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), attr_var_as_cell!(11) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(1) ); assert_eq!(iter.next(), None); } assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(1)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(1)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(3)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), list_loc_as_cell!(4)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), str_loc_as_cell!(6)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), heap_loc_as_cell!(8)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), atom_as_cell!(f_atom, 1)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), heap_loc_as_cell!(11)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), list_loc_as_cell!(9)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[9]), heap_loc_as_cell!(9)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[10]), empty_list_as_cell!()); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[11]), attr_var_as_cell!(11)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[12]), heap_loc_as_cell!(13)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[13]), list_loc_as_cell!(14)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[14]), str_loc_as_cell!(16)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[15]), heap_loc_as_cell!(19)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[16]), atom_as_cell!(clpz_atom, 2)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[17]), atom_as_cell!(a_atom)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[18]), atom_as_cell!(b_atom)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[19]), list_loc_as_cell!(20)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[20]), str_loc_as_cell!(22)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[21]), empty_list_as_cell!()); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[22]), atom_as_cell!(p_atom, 1)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[23]), heap_loc_as_cell!(23)); wam.machine_st.heap.clear(); { let mut iter = stackless_preorder_iter( &mut wam.machine_st.heap, fixnum_as_cell!(Fixnum::build_with(0)) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), fixnum_as_cell!(Fixnum::build_with(0)) ); assert_eq!(iter.next(), None); } all_cells_unmarked(&wam.machine_st.heap); assert_eq!(wam.machine_st.heap.len(), 0); wam.machine_st.heap.clear(); wam.machine_st.heap.push(str_loc_as_cell!(1)); wam.machine_st.heap.push(atom_as_cell!(atom!("g"),2)); wam.machine_st.heap.push(heap_loc_as_cell!(0)); wam.machine_st.heap.push(atom_as_cell!(atom!("y"))); { let mut iter = stackless_preorder_iter( &mut wam.machine_st.heap, str_loc_as_cell!(1), ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(atom!("g"),2) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(atom!("y")) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(1) ); assert!(iter.next().is_none()); } all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.clear(); wam.machine_st.heap.push(atom_as_cell!(atom!("g"),2)); wam.machine_st.heap.push(str_loc_as_cell!(0)); wam.machine_st.heap.push(atom_as_cell!(atom!("y"))); { let mut iter = stackless_preorder_iter( &mut wam.machine_st.heap, str_loc_as_cell!(0), ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(atom!("g"),2) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(atom!("y")) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(0) ); assert!(iter.next().is_none()); } all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.clear(); wam.machine_st.heap.push(str_loc_as_cell!(1)); wam.machine_st.heap.push(atom_as_cell!(atom!("g"), 2)); wam.machine_st.heap.push(heap_loc_as_cell!(0)); wam.machine_st.heap.push(atom_as_cell!(atom!("y"))); wam.machine_st.heap.push(atom_as_cell!(atom!("="), 2)); wam.machine_st.heap.push(atom_as_cell!(atom!("X"))); wam.machine_st.heap.push(heap_loc_as_cell!(0)); wam.machine_st.heap.push(list_loc_as_cell!(8)); wam.machine_st.heap.push(str_loc_as_cell!(4)); wam.machine_st.heap.push(empty_list_as_cell!()); { let mut iter = stackless_preorder_iter( &mut wam.machine_st.heap, heap_loc_as_cell!(7), ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(8) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), empty_list_as_cell!() ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(atom!("="), 2) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(atom!("g"), 2) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(atom!("y")) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(0) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(atom!("X")) ); assert!(iter.next().is_none()); } all_cells_unmarked(&wam.machine_st.heap); assert_eq!(wam.machine_st.heap[0], str_loc_as_cell!(1)); assert_eq!(wam.machine_st.heap[1], atom_as_cell!(atom!("g"), 2)); assert_eq!(wam.machine_st.heap[2], heap_loc_as_cell!(0)); assert_eq!(wam.machine_st.heap[3], atom_as_cell!(atom!("y"))); assert_eq!(wam.machine_st.heap[4], atom_as_cell!(atom!("="), 2)); assert_eq!(wam.machine_st.heap[5], atom_as_cell!(atom!("X"))); assert_eq!(wam.machine_st.heap[6], heap_loc_as_cell!(0)); assert_eq!(wam.machine_st.heap[7], list_loc_as_cell!(8)); assert_eq!(wam.machine_st.heap[8], str_loc_as_cell!(4)); assert_eq!(wam.machine_st.heap[9], empty_list_as_cell!()); wam.machine_st.heap.clear(); wam.machine_st.heap.push(atom_as_cell!(atom!("f"), 2)); wam.machine_st.heap.push(heap_loc_as_cell!(1)); wam.machine_st.heap.push(heap_loc_as_cell!(1)); { let mut iter = stackless_preorder_iter( &mut wam.machine_st.heap, str_loc_as_cell!(0), ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(atom!("f"), 2) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(1) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(1) ); assert!(iter.next().is_none()); } assert_eq!(wam.machine_st.heap[0], atom_as_cell!(atom!("f"), 2)); assert_eq!(wam.machine_st.heap[1], heap_loc_as_cell!(1)); assert_eq!(wam.machine_st.heap[2], heap_loc_as_cell!(1)); } #[test] fn heap_stackful_iter_tests() { let mut wam = MockWAM::new(); let f_atom = atom!("f"); let a_atom = atom!("a"); let b_atom = atom!("b"); wam.machine_st.heap .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); { let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 2) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!(iter.next(), None); } wam.machine_st.heap.clear(); wam.machine_st.heap.extend(functor!( f_atom, [ atom(a_atom), atom(b_atom), atom(a_atom), cell(str_loc_as_cell!(0)) ] )); for _ in 0..20 { let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 4) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(0)); assert_eq!(iter.next(), None); } wam.machine_st.heap.clear(); { wam.machine_st.heap.push(heap_loc_as_cell!(0)); let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); let mut var = heap_loc_as_cell!(0); // self-referencing variables are copied with their forwarding // and marking bits set to true. it suffices to check only the // forwarding bit to detect cycles of all kinds, including // unbound/self-referencing variables. var.set_forwarding_bit(true); var.set_mark_bit(true); assert_eq!(iter.next().unwrap(), var); assert_eq!(iter.next(), None); } wam.machine_st.heap.clear(); { // mutually referencing variables. wam.machine_st.heap.push(heap_loc_as_cell!(1)); wam.machine_st.heap.push(heap_loc_as_cell!(0)); let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(0) ); assert_eq!(iter.next(), None); } wam.machine_st.heap.clear(); // term is: [a, b] wam.machine_st.heap.push(list_loc_as_cell!(1)); wam.machine_st.heap.push(atom_as_cell!(a_atom)); wam.machine_st.heap.push(list_loc_as_cell!(3)); wam.machine_st.heap.push(atom_as_cell!(b_atom)); wam.machine_st.heap.push(empty_list_as_cell!()); { let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(1) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), empty_list_as_cell!() ); assert_eq!(iter.next(), None); } wam.machine_st.heap.pop(); // now make the list cyclic. wam.machine_st.heap.push(heap_loc_as_cell!(0)); { let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); // the cycle will be iterated twice before being detected. assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(1) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(1) ); assert_eq!(iter.next(), None); } { let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); // cut the iteration short to check that all cells are // unmarked and unforwarded by the Drop instance of // StackfulPreOrderHeapIter. assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(1) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); } all_cells_unmarked(&wam.machine_st.heap); assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1)); assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom)); assert_eq!(wam.machine_st.heap[2], list_loc_as_cell!(3)); assert_eq!(wam.machine_st.heap[3], atom_as_cell!(b_atom)); assert_eq!(wam.machine_st.heap[4], heap_loc_as_cell!(0)); wam.machine_st.heap.clear(); // first a 'dangling' partial string, later modified to be a // two-part complete string, then a three-part cyclic string // involving an uncompacted list of chars. let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "abc ", &mut wam.machine_st.atom_tbl); let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; { let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(1), ); assert_eq!(iter.next(), None); } // here wam.machine_st.heap.pop(); wam.machine_st.heap.push(heap_loc_as_cell!(2)); let pstr_second_var_cell = put_partial_string(&mut wam.machine_st.heap, "def", &mut wam.machine_st.atom_tbl); let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; { let mut iter = stackful_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(3), ); assert_eq!(iter.next(), None); } wam.machine_st.heap.pop(); wam.machine_st.heap.push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1)); wam.machine_st.heap.push(pstr_offset_as_cell!(0)); wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0i64))); { let mut iter = stackful_preorder_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); let pstr_offset_cell = pstr_offset_as_cell!(0); // pstr_offset_cell.set_forwarding_bit(true); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell); assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(0i64))); assert_eq!(iter.next(), None); } /* { let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0); let string: String = iter.chars().collect(); assert_eq!(string, "abc def"); } */ wam.machine_st.heap.pop(); wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(1i64))); { let mut iter = stackful_preorder_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); let pstr_offset_cell = pstr_offset_as_cell!(0); // pstr_offset_cell.set_forwarding_bit(true); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell); assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(1i64))); let h = iter.focus(); assert_eq!(h, 5); assert_eq!(unmark_cell_bits!(iter.heap[4]), pstr_offset_as_cell!(0)); assert_eq!(unmark_cell_bits!(iter.heap[5]), fixnum_as_cell!(Fixnum::build_with(1i64))); assert_eq!(iter.next(), None); } wam.machine_st.heap.clear(); let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]); wam.machine_st.heap.push(list_loc_as_cell!(1)); wam.machine_st.heap.push(str_loc_as_cell!(5)); wam.machine_st.heap.push(list_loc_as_cell!(3)); wam.machine_st.heap.push(str_loc_as_cell!(5)); wam.machine_st.heap.push(empty_list_as_cell!()); wam.machine_st.heap.extend(functor); { let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(1) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), empty_list_as_cell!() ); assert_eq!(iter.next(), None); } all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap[4] = list_loc_as_cell!(1); { let mut iter = stackful_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(1) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); let mut link_back = list_loc_as_cell!(1); link_back.set_forwarding_bit(true); assert_eq!(iter.next().unwrap(), link_back); assert_eq!(iter.next(), None); } all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.clear(); wam.machine_st.heap.push(list_loc_as_cell!(1)); wam.machine_st.heap.push(list_loc_as_cell!(1)); wam.machine_st.heap.push(list_loc_as_cell!(1)); { let mut iter = StackfulPreOrderHeapIter::new( &mut wam.machine_st.heap, heap_loc_as_cell!(0), ); let mut cyclic_link = list_loc_as_cell!(1); cyclic_link.set_forwarding_bit(true); assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(1) ); assert_eq!(iter.next().unwrap(), cyclic_link); assert_eq!(iter.next(), None); } all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.clear(); wam.machine_st.heap.push(pstr_as_cell!(atom!("a string"))); wam.machine_st.heap.push(empty_list_as_cell!()); { let mut iter = stackful_preorder_iter( &mut wam.machine_st.heap, heap_loc_as_cell!(0), ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), pstr_as_cell!(atom!("a string")) ); assert_eq!( iter.next().unwrap(), empty_list_as_cell!() ); assert_eq!(iter.next(), None); } all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.clear(); wam.machine_st.heap.push(str_loc_as_cell!(1)); wam.machine_st.heap.push(atom_as_cell!(atom!("g"), 2)); wam.machine_st.heap.push(heap_loc_as_cell!(0)); wam.machine_st.heap.push(atom_as_cell!(atom!("y"))); wam.machine_st.heap.push(atom_as_cell!(atom!("="), 2)); wam.machine_st.heap.push(atom_as_cell!(atom!("X"))); wam.machine_st.heap.push(heap_loc_as_cell!(0)); wam.machine_st.heap.push(list_loc_as_cell!(8)); wam.machine_st.heap.push(str_loc_as_cell!(4)); wam.machine_st.heap.push(empty_list_as_cell!()); { let mut iter = stackful_preorder_iter( &mut wam.machine_st.heap, heap_loc_as_cell!(0), ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(atom!("g"), 2) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(1) ); assert_eq!( iter.next().unwrap(), atom_as_cell!(atom!("y")) ); assert!(iter.next().is_none()); } } #[test] fn heap_stackful_post_order_iter() { let mut wam = MockWAM::new(); let f_atom = atom!("f"); let a_atom = atom!("a"); let b_atom = atom!("b"); wam.machine_st.heap .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); { let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 2) ); assert_eq!(iter.next(), None); } wam.machine_st.heap.clear(); wam.machine_st.heap.extend(functor!( f_atom, [ atom(a_atom), atom(b_atom), atom(a_atom), cell(str_loc_as_cell!(0)) ] )); for _ in 0..20 { // 0000 { let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 4) ); assert_eq!(iter.next(), None); } wam.machine_st.heap.clear(); { wam.machine_st.heap.push(heap_loc_as_cell!(0)); let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); let mut var = heap_loc_as_cell!(0); // self-referencing variables are copied with their forwarding // and marking bits set to true. it suffices to check only the // forwarding bit to detect cycles of all kinds, including // unbound/self-referencing variables. var.set_forwarding_bit(true); var.set_mark_bit(true); assert_eq!(iter.next().unwrap(), var); assert_eq!(iter.next(), None); } wam.machine_st.heap.clear(); { // mutually referencing variables. wam.machine_st.heap.push(heap_loc_as_cell!(1)); wam.machine_st.heap.push(heap_loc_as_cell!(0)); let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(0) ); assert_eq!(iter.next(), None); } wam.machine_st.heap.clear(); // term is: [a, b] wam.machine_st.heap.push(list_loc_as_cell!(1)); wam.machine_st.heap.push(atom_as_cell!(a_atom)); wam.machine_st.heap.push(list_loc_as_cell!(3)); wam.machine_st.heap.push(atom_as_cell!(b_atom)); wam.machine_st.heap.push(empty_list_as_cell!()); { let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), empty_list_as_cell!() ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(1) ); assert_eq!(iter.next(), None); } wam.machine_st.heap.pop(); // now make the list cyclic. wam.machine_st.heap.push(heap_loc_as_cell!(0)); { let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); // the cycle will be iterated twice before being detected. assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(1) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(1) ); assert_eq!(iter.next(), None); } { let mut iter = stackful_post_order_iter( &mut wam.machine_st.heap, heap_loc_as_cell!(0), ); // cut the iteration short to check that all cells are // unmarked and unforwarded by the Drop instance of // StackfulPreOrderHeapIter. assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); } all_cells_unmarked(&wam.machine_st.heap); assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1)); assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom)); assert_eq!(wam.machine_st.heap[2], list_loc_as_cell!(3)); assert_eq!(wam.machine_st.heap[3], atom_as_cell!(b_atom)); assert_eq!(wam.machine_st.heap[4], heap_loc_as_cell!(0)); wam.machine_st.heap.clear(); // first a 'dangling' partial string, later modified to be a // two-part complete string, then a three-part cyclic string // involving an uncompacted list of chars. let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "abc ", &mut wam.machine_st.atom_tbl); let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; { let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(1), ); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); assert_eq!(iter.next(), None); } wam.machine_st.heap.pop(); wam.machine_st.heap.push(pstr_loc_as_cell!(2)); let pstr_second_var_cell = put_partial_string(&mut wam.machine_st.heap, "def", &mut wam.machine_st.atom_tbl); let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; { let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(3), ); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); assert_eq!(iter.next(), None); } wam.machine_st.heap.pop(); wam.machine_st.heap.push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1)); wam.machine_st.heap.push(pstr_offset_as_cell!(0)); wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0i64))); { let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(0i64))); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0)); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); assert_eq!(iter.next(), None); } wam.machine_st.heap.pop(); wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(1i64))); { let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(1i64))); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0)); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); assert_eq!(iter.next(), None); } wam.machine_st.heap.clear(); let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]); wam.machine_st.heap.push(list_loc_as_cell!(1)); wam.machine_st.heap.push(str_loc_as_cell!(5)); wam.machine_st.heap.push(list_loc_as_cell!(3)); wam.machine_st.heap.push(str_loc_as_cell!(5)); wam.machine_st.heap.push(empty_list_as_cell!()); wam.machine_st.heap.extend(functor); { let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), empty_list_as_cell!() ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(1) ); assert_eq!(iter.next(), None); } all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap[4] = list_loc_as_cell!(1); { let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 3) ); let mut link_back = list_loc_as_cell!(1); link_back.set_forwarding_bit(true); assert_eq!(iter.next().unwrap(), link_back); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(1) ); assert_eq!(iter.next(), None); } all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.clear(); } #[test] fn heap_stackless_post_order_iter() { let mut wam = MockWAM::new(); let f_atom = atom!("f"); let a_atom = atom!("a"); let b_atom = atom!("b"); wam.machine_st.heap.extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); { let mut iter = stackless_post_order_iter( &mut wam.machine_st.heap, str_loc_as_cell!(0), ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 2) ); assert_eq!(iter.next(), None); } wam.machine_st.heap.clear(); wam.machine_st.heap.extend(functor!( f_atom, [ atom(a_atom), atom(b_atom), atom(a_atom), cell(str_loc_as_cell!(0)) ] )); for _ in 0..20 { let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, str_loc_as_cell!(0)); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 4) ); assert_eq!(iter.next(), None); } wam.machine_st.heap.clear(); { wam.machine_st.heap.push(heap_loc_as_cell!(0)); let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(0) ); assert_eq!(iter.next(), None); } wam.machine_st.heap.clear(); { // mutually referencing variables. wam.machine_st.heap.push(heap_loc_as_cell!(1)); wam.machine_st.heap.push(heap_loc_as_cell!(0)); let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(0) ); assert_eq!(iter.next(), None); } wam.machine_st.heap.clear(); // term is: [a, b] wam.machine_st.heap.push(list_loc_as_cell!(1)); wam.machine_st.heap.push(atom_as_cell!(a_atom)); wam.machine_st.heap.push(list_loc_as_cell!(3)); wam.machine_st.heap.push(atom_as_cell!(b_atom)); wam.machine_st.heap.push(empty_list_as_cell!()); { let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), empty_list_as_cell!() ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(1) ); assert_eq!(iter.next(), None); } wam.machine_st.heap.pop(); // now make the list cyclic. wam.machine_st.heap.push(heap_loc_as_cell!(0)); { let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); // the cycle will be iterated twice before being detected. assert_eq!( unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(0) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(1) ); assert_eq!(iter.next(), None); } { let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); // cut the iteration short to check that all cells are // unmarked and unforwarded by the Drop instance of // StacklessPreOrderHeapIter. assert_eq!( unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(0) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); } all_cells_unmarked(&wam.machine_st.heap); assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1)); assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom)); assert_eq!(wam.machine_st.heap[2], list_loc_as_cell!(3)); assert_eq!(wam.machine_st.heap[3], atom_as_cell!(b_atom)); assert_eq!(wam.machine_st.heap[4], heap_loc_as_cell!(0)); wam.machine_st.heap.clear(); // first a 'dangling' partial string, later modified to be a // two-part complete string, then a three-part cyclic string // involving an uncompacted list of chars. let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "abc ", &mut wam.machine_st.atom_tbl); let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; { let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(1), ); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); assert_eq!(iter.next(), None); } wam.machine_st.heap.pop(); wam.machine_st.heap.push(pstr_loc_as_cell!(2)); let pstr_second_var_cell = put_partial_string( &mut wam.machine_st.heap, "def", &mut wam.machine_st.atom_tbl, ); let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; { let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(3), ); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); assert_eq!(iter.next(), None); } all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.pop(); wam.machine_st.heap.push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1)); wam.machine_st.heap.push(pstr_offset_as_cell!(0)); wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0))); { let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); let mut pstr_loc_cell = pstr_loc_as_cell!(0); pstr_loc_cell.set_forwarding_bit(true); // assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(0i64))); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0)); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0)); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); assert_eq!(iter.next(), None); } all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.pop(); wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(1))); { let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); //assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(1))); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0)); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0)); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); assert_eq!(iter.next(), None); } wam.machine_st.heap.clear(); let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]); wam.machine_st.heap.push(list_loc_as_cell!(1)); wam.machine_st.heap.push(str_loc_as_cell!(5)); wam.machine_st.heap.push(list_loc_as_cell!(3)); wam.machine_st.heap.push(str_loc_as_cell!(5)); wam.machine_st.heap.push(empty_list_as_cell!()); wam.machine_st.heap.extend(functor); { let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), empty_list_as_cell!() ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(1) ); assert_eq!(iter.next(), None); } all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap[4] = list_loc_as_cell!(1); { let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(b_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 3) ); assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(3) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(1) ); assert_eq!(iter.next(), None); } all_cells_unmarked(&wam.machine_st.heap); } }