]> git.lizzy.rs Git - rust.git/commitdiff
Major revision to the dropck_legal_cycles test.
authorFelix S. Klock II <pnkfelix@pnkfx.org>
Fri, 9 Oct 2015 16:02:37 +0000 (18:02 +0200)
committerFelix S. Klock II <pnkfelix@pnkfx.org>
Fri, 9 Oct 2015 16:04:18 +0000 (18:04 +0200)
1. Added big comment block explaining the test framework.

2. Added tests exericising Rc and Arc. This was inspired by a comment
   from eefriedman on PR #28861.

3. Made the cycle-detection not issue false-positives on acyclic dags.

   Doing this efficiently required revising the framework; instead of
   visiting all children (i.e. doing a traversal), now each test is
   responsible for supplying the path that will act as a witness to
   the cycle.

   Luckily for me, all of the pre-existing tests worked with a trivial
   path built from "always tke your first left", but new tests I added
   did require other input paths (i.e., "first turn right, then left".

   (The path representation is a bit-string and its branches are
    n-ary, not word phrases and binary branches as you might think
    from the outline above.)

src/test/run-pass/dropck_legal_cycles.rs

index 2770260a10e1c44ebb18e661edf122c6bc34afc5..a31df0fd93e16a1aaca8508d97feec1bf52ae3bb 100644 (file)
 // through the collection, for every collection type that supports
 // this.
 
-#![feature(vecmap)]
+// HIGH LEVEL DESCRIPTION OF THE TEST ARCHITECTURE
+// -----------------------------------------------
+//
+// We pick a data structure and want to make a cyclic construction
+// from it. Each test of interest is labelled starting with "Cycle N:
+// { ... }" where N is the test number and the "..."`is filled in with
+// a graphviz-style description of the graph structure that the
+// author believes is being made. So "{ a -> b, b -> (c,d), (c,d) -> e }"
+// describes a line connected to a diamond:
+//
+//                           c
+//                          / \
+//                     a - b   e
+//                          \ /
+//                           d
+//
+// (Note that the above directed graph is actually acyclic.)
+//
+// The different graph structures are often composed of different data
+// types. Some may be built atop `Vec`, others atop `HashMap`, etc.
+//
+// For each graph structure, we actually *confirm* that a cycle exists
+// (as a safe-guard against a test author accidentally leaving it out)
+// by traversing each graph and "proving" that a cycle exists within it.
+//
+// To do this, while trying to keep the code uniform (despite working
+// with different underlying collection and smart-pointer types), we
+// have a standard traversal API:
+//
+// 1. every node in the graph carries a `mark` (a u32, init'ed to 0).
+//
+// 2. every node provides a method to visit its children
+//
+// 3. a traversal attmepts to visit the nodes of the graph and prove that
+//    it sees the same node twice. It does this by setting the mark of each
+//    node to a fresh non-zero value, and if it sees the current mark, it
+//    "knows" that it must have found a cycle, and stops attempting further
+//    traversal.
+//
+// 4. each traversal is controlled by a bit-string that tells it which child
+//    it visit when it can take different paths. As a simple example,
+//    in a binary tree, 0 could mean "left" (and 1, "right"), so that
+//    "00010" means "left, left, left, right, left". (In general it will
+//    read as many bits as it needs to choose one child.)
+//
+//    The graphs in this test are all meant to be very small, and thus
+//    short bitstrings of less than 64 bits should always suffice.
+//
+//    (An earlier version of this test infrastructure simply had any
+//    given traversal visit all children it encountered, in a
+//    depth-first manner; one problem with this approach is that an
+//    acyclic graph can still have sharing, which would then be treated
+//    as a repeat mark and reported as a detected cycle.)
+//
+// The travseral code is a little more complicated because it has been
+// programmed in a somewhat defensive manner. For example it also has
+// a max threshold for the number of nodes it will visit, to guard
+// against scenarios where the nodes are not correctly setting their
+// mark when asked. There are various other methods not discussed here
+// that are for aiding debugging the test when it runs, such as the
+// `name` method that all nodes provide.
+//
+// So each test:
+//
+// 1. allocates the nodes in the graph,
+//
+// 2. sets up the links in the graph,
+//
+// 3. clones the "ContextData"
+//
+// 4. chooses a new current mark value for this test
+//
+// 5. initiates a traversal, potentially from multiple starting points
+//    (aka "roots"), with a given control-string (potentially a
+//    different string for each root). if it does start from a
+//    distinct root, then such a test should also increment the
+//    current mark value, so that this traversal is considered
+//    distinct from the prior one on this graph structure.
+//
+//    Note that most of the tests work with the default control string
+//    of all-zeroes.
+//
+// 6. assert that the context confirms that it actually saw a cycle (since a traversal
+//    might have terminated, e.g. on a tree structure that contained no cycles).
 
-use std::cell::Cell;
+use std::cell::{Cell, RefCell};
 use std::cmp::Ordering;
 use std::collections::BinaryHeap;
 use std::collections::HashMap;
 use std::collections::btree_map::BTreeMap;
 use std::collections::btree_set::BTreeSet;
 use std::hash::{Hash, Hasher};
+use std::rc::Rc;
+use std::sync::{Arc, RwLock, Mutex};
 
 const PRINT: bool = false;
 
@@ -47,8 +132,28 @@ pub fn main() {
         skipped: 0,
         curr_mark: 0,
         saw_prev_marked: false,
+        control_bits: 0,
     };
 
+    // SANITY CHECK FOR TEST SUITE (thus unnumbered)
+    // Not a cycle: { v[0] -> (v[1], v[2]), v[1] -> v[3], v[2] -> v[3] };
+    let v: Vec<S2> = vec![Named::new("s0"),
+                          Named::new("s1"),
+                          Named::new("s2"),
+                          Named::new("s3")];
+    v[0].next.set((Some(&v[1]), Some(&v[2])));
+    v[1].next.set((Some(&v[3]), None));
+    v[2].next.set((Some(&v[3]), None));
+    v[3].next.set((None, None));
+
+    let mut c = c_orig.clone();
+    c.curr_mark = 10;
+    assert!(!c.saw_prev_marked);
+    v[0].descend_into_self(&mut c);
+    assert!(!c.saw_prev_marked); // <-- different from below, b/c acyclic above
+
+    if PRINT { println!(""); }
+
     // Cycle 1: { v[0] -> v[1], v[1] -> v[0] };
     // does not exercise `v` itself
     let v: Vec<S> = vec![Named::new("s0"),
@@ -59,7 +164,7 @@ pub fn main() {
     let mut c = c_orig.clone();
     c.curr_mark = 10;
     assert!(!c.saw_prev_marked);
-    v[0].for_each_child(&mut c);
+    v[0].descend_into_self(&mut c);
     assert!(c.saw_prev_marked);
 
     if PRINT { println!(""); }
@@ -72,7 +177,7 @@ pub fn main() {
     let mut c = c_orig.clone();
     c.curr_mark = 20;
     assert!(!c.saw_prev_marked);
-    v.for_each_child(&mut c);
+    v.descend_into_self(&mut c);
     assert!(c.saw_prev_marked);
 
     if PRINT { println!(""); }
@@ -93,7 +198,7 @@ pub fn main() {
     for (key, _) in h.iter() {
         c.curr_mark += 1;
         c.saw_prev_marked = false;
-        key.for_each_child(&mut c);
+        key.descend_into_self(&mut c);
         assert!(c.saw_prev_marked);
     }
 
@@ -115,7 +220,7 @@ pub fn main() {
     for (key, _) in h.iter() {
         c.curr_mark += 1;
         c.saw_prev_marked = false;
-        key.for_each_child(&mut c);
+        key.descend_into_self(&mut c);
         assert!(c.saw_prev_marked);
         // break;
     }
@@ -133,7 +238,7 @@ pub fn main() {
     let mut c = c_orig.clone();
     c.curr_mark = 50;
     assert!(!c.saw_prev_marked);
-    vd[0].for_each_child(&mut c);
+    vd[0].descend_into_self(&mut c);
     assert!(c.saw_prev_marked);
 
     if PRINT { println!(""); }
@@ -148,7 +253,7 @@ pub fn main() {
     let mut c = c_orig.clone();
     c.curr_mark = 60;
     assert!(!c.saw_prev_marked);
-    vd[0].for_each_child(&mut c);
+    vd[0].descend_into_self(&mut c);
     assert!(c.saw_prev_marked);
 
     if PRINT { println!(""); }
@@ -163,7 +268,7 @@ pub fn main() {
     let mut c = c_orig.clone();
     c.curr_mark = 70;
     assert!(!c.saw_prev_marked);
-    vm[&0].for_each_child(&mut c);
+    vm[&0].descend_into_self(&mut c);
     assert!(c.saw_prev_marked);
 
     if PRINT { println!(""); }
@@ -181,7 +286,7 @@ pub fn main() {
     for e in &ll {
         c.curr_mark += 1;
         c.saw_prev_marked = false;
-        e.for_each_child(&mut c);
+        e.descend_into_self(&mut c);
         assert!(c.saw_prev_marked);
         // break;
     }
@@ -201,7 +306,7 @@ pub fn main() {
     for b in &bh {
         c.curr_mark += 1;
         c.saw_prev_marked = false;
-        b.for_each_child(&mut c);
+        b.descend_into_self(&mut c);
         assert!(c.saw_prev_marked);
         // break;
     }
@@ -222,7 +327,7 @@ pub fn main() {
     for (k, _) in &btm {
         c.curr_mark += 1;
         c.saw_prev_marked = false;
-        k.for_each_child(&mut c);
+        k.descend_into_self(&mut c);
         assert!(c.saw_prev_marked);
         // break;
     }
@@ -242,10 +347,98 @@ pub fn main() {
     for b in &bts {
         c.curr_mark += 1;
         c.saw_prev_marked = false;
-        b.for_each_child(&mut c);
+        b.descend_into_self(&mut c);
         assert!(c.saw_prev_marked);
         // break;
     }
+
+    if PRINT { println!(""); }
+
+    // Cycle 11: { rc0 -> (rc1, rc2), rc1 -> (), rc2 -> rc0 }
+    let (rc0, rc1, rc2): (RCRC, RCRC, RCRC);
+    rc0 = RCRC::new("rcrc0");
+    rc1 = RCRC::new("rcrc1");
+    rc2 = RCRC::new("rcrc2");
+    rc0.0.borrow_mut().children.0 = Some(&rc1);
+    rc0.0.borrow_mut().children.1 = Some(&rc2);
+    rc2.0.borrow_mut().children.0 = Some(&rc0);
+
+    let mut c = c_orig.clone();
+    c.control_bits = 0b1;
+    c.curr_mark = 110;
+    assert!(!c.saw_prev_marked);
+    rc0.descend_into_self(&mut c);
+    assert!(c.saw_prev_marked);
+
+    if PRINT { println!(""); }
+
+    // We want to take the previous Rc case and generalize it to Arc.
+    //
+    // We can use refcells if we're single-threaded (as this test is).
+    // If one were to generalize these constructions to a
+    // multi-threaded context, then it might seem like we could choose
+    // between either a RwLock or a Mutex to hold the owned arcs on
+    // each node.
+    //
+    // Part of the point of this test is to actually confirm that the
+    // cycle exists by traversing it. We can do that just fine with an
+    // RwLock (since we can grab the child pointers in read-only
+    // mode), but we cannot lock a std::sync::Mutex to guard reading
+    // from each node via the same pattern, since once you hit the
+    // cycle, you'll be trying to acquring the same lock twice.
+    // (We deal with this by exiting the traversal early if try_lock fails.)
+
+    // Cycle 12: { arc0 -> (arc1, arc2), arc1 -> (), arc2 -> arc0 }, refcells
+    let (arc0, arc1, arc2): (ARCRC, ARCRC, ARCRC);
+    arc0 = ARCRC::new("arcrc0");
+    arc1 = ARCRC::new("arcrc1");
+    arc2 = ARCRC::new("arcrc2");
+    arc0.0.borrow_mut().children.0 = Some(&arc1);
+    arc0.0.borrow_mut().children.1 = Some(&arc2);
+    arc2.0.borrow_mut().children.0 = Some(&arc0);
+
+    let mut c = c_orig.clone();
+    c.control_bits = 0b1;
+    c.curr_mark = 110;
+    assert!(!c.saw_prev_marked);
+    arc0.descend_into_self(&mut c);
+    assert!(c.saw_prev_marked);
+
+    if PRINT { println!(""); }
+
+    // Cycle 13: { arc0 -> (arc1, arc2), arc1 -> (), arc2 -> arc0 }, rwlocks
+    let (arc0, arc1, arc2): (ARCRW, ARCRW, ARCRW);
+    arc0 = ARCRW::new("arcrw0");
+    arc1 = ARCRW::new("arcrw1");
+    arc2 = ARCRW::new("arcrw2");
+    arc0.0.write().unwrap().children.0 = Some(&arc1);
+    arc0.0.write().unwrap().children.1 = Some(&arc2);
+    arc2.0.write().unwrap().children.0 = Some(&arc0);
+
+    let mut c = c_orig.clone();
+    c.control_bits = 0b1;
+    c.curr_mark = 110;
+    assert!(!c.saw_prev_marked);
+    arc0.descend_into_self(&mut c);
+    assert!(c.saw_prev_marked);
+
+    if PRINT { println!(""); }
+
+    // Cycle 14: { arc0 -> (arc1, arc2), arc1 -> (), arc2 -> arc0 }, mutexs
+    let (arc0, arc1, arc2): (ARCM, ARCM, ARCM);
+    arc0 = ARCM::new("arcm0");
+    arc1 = ARCM::new("arcm1");
+    arc2 = ARCM::new("arcm2");
+    arc0.1.lock().unwrap().children.0 = Some(&arc1);
+    arc0.1.lock().unwrap().children.1 = Some(&arc2);
+    arc2.1.lock().unwrap().children.0 = Some(&arc0);
+
+    let mut c = c_orig.clone();
+    c.control_bits = 0b1;
+    c.curr_mark = 110;
+    assert!(!c.saw_prev_marked);
+    arc0.descend_into_self(&mut c);
+    assert!(c.saw_prev_marked);
 }
 
 trait Named {
@@ -276,6 +469,26 @@ fn mark(&self) -> u32 { self.mark.get() }
     fn set_mark(&self, mark: u32) { self.mark.set(mark); }
 }
 
+struct S2<'a> {
+    name: &'static str,
+    mark: Cell<u32>,
+    next: Cell<(Option<&'a S2<'a>>, Option<&'a S2<'a>>)>,
+}
+
+impl<'a> Named for S2<'a> {
+    fn new<'b>(name: &'static str) -> S2<'b> {
+        S2 { name: name, mark: Cell::new(0), next: Cell::new((None, None)) }
+    }
+    fn name(&self) -> &str { self.name }
+}
+
+impl<'a> Marked<u32> for S2<'a> {
+    fn mark(&self) -> u32 { self.mark.get() }
+    fn set_mark(&self, mark: u32) {
+        self.mark.set(mark);
+    }
+}
+
 struct V<'a> {
     name: &'static str,
     mark: Cell<u32>,
@@ -549,8 +762,168 @@ fn cmp(&self, rhs: &BTS<'a>) -> Ordering {
     }
 }
 
+#[derive(Clone)]
+struct RCRCData<'a> {
+    name: &'static str,
+    mark: Cell<u32>,
+    children: (Option<&'a RCRC<'a>>, Option<&'a RCRC<'a>>),
+}
+#[derive(Clone)]
+struct RCRC<'a>(Rc<RefCell<RCRCData<'a>>>);
+
+impl<'a> Named for RCRC<'a> {
+    fn new(name: &'static str) -> Self {
+        RCRC(Rc::new(RefCell::new(RCRCData {
+            name: name, mark: Cell::new(0), children: (None, None), })))
+    }
+    fn name(&self) -> &str { self.0.borrow().name }
+}
+
+impl<'a> Marked<u32> for RCRC<'a> {
+    fn mark(&self) -> u32 { self.0.borrow().mark.get() }
+    fn set_mark(&self, mark: u32) { self.0.borrow().mark.set(mark); }
+}
+
+impl<'a> Children<'a> for RCRC<'a> {
+    fn count_children(&self) -> usize { 2 }
+    fn descend_one_child<C>(&self, context: &mut C, index: usize)
+        where C: Context + PrePost<Self>, Self: Sized
+    {
+        let children = &self.0.borrow().children;
+        let child = match index {
+            0 => if let Some(child) = children.0 { child } else { return; },
+            1 => if let Some(child) = children.1 { child } else { return; },
+            _ => panic!("bad children"),
+        };
+        // println!("S2 {} descending into child {} at index {}", self.name, child.name, index);
+        child.descend_into_self(context);
+    }
+}
+#[derive(Clone)]
+struct ARCRCData<'a> {
+    name: &'static str,
+    mark: Cell<u32>,
+    children: (Option<&'a ARCRC<'a>>, Option<&'a ARCRC<'a>>),
+}
+#[derive(Clone)]
+struct ARCRC<'a>(Arc<RefCell<ARCRCData<'a>>>);
+
+impl<'a> Named for ARCRC<'a> {
+    fn new(name: &'static str) -> Self {
+        ARCRC(Arc::new(RefCell::new(ARCRCData {
+            name: name, mark: Cell::new(0), children: (None, None), })))
+    }
+    fn name(&self) -> &str { self.0.borrow().name }
+}
+
+impl<'a> Marked<u32> for ARCRC<'a> {
+    fn mark(&self) -> u32 { self.0.borrow().mark.get() }
+    fn set_mark(&self, mark: u32) { self.0.borrow().mark.set(mark); }
+}
+
+impl<'a> Children<'a> for ARCRC<'a> {
+    fn count_children(&self) -> usize { 2 }
+    fn descend_one_child<C>(&self, context: &mut C, index: usize)
+        where C: Context + PrePost<Self>, Self: Sized
+    {
+        let children = &self.0.borrow().children;
+        match index {
+            0 => if let Some(ref child) = children.0 {
+                child.descend_into_self(context);
+            },
+            1 => if let Some(ref child) = children.1 {
+                child.descend_into_self(context);
+            },
+            _ => panic!("bad children!"),
+        }
+    }
+}
+
+#[derive(Clone)]
+struct ARCMData<'a> {
+    mark: Cell<u32>,
+    children: (Option<&'a ARCM<'a>>, Option<&'a ARCM<'a>>),
+}
+
+#[derive(Clone)]
+struct ARCM<'a>(&'static str, Arc<Mutex<ARCMData<'a>>>);
+
+impl<'a> Named for ARCM<'a> {
+    fn new(name: &'static str) -> Self {
+        ARCM(name, Arc::new(Mutex::new(ARCMData {
+            mark: Cell::new(0), children: (None, None), })))
+    }
+    fn name(&self) -> &str { self.0 }
+}
+
+impl<'a> Marked<u32> for ARCM<'a> {
+    fn mark(&self) -> u32 { self.1.lock().unwrap().mark.get() }
+    fn set_mark(&self, mark: u32) { self.1.lock().unwrap().mark.set(mark); }
+}
+
+impl<'a> Children<'a> for ARCM<'a> {
+    fn count_children(&self) -> usize { 2 }
+    fn descend_one_child<C>(&self, context: &mut C, index: usize)
+        where C: Context + PrePost<Self>, Self: Sized
+    {
+        let ref children = if let Ok(data) = self.1.try_lock() {
+            data.children
+        } else { return; };
+        match index {
+            0 => if let Some(ref child) = children.0 {
+                child.descend_into_self(context);
+            },
+            1 => if let Some(ref child) = children.1 {
+                child.descend_into_self(context);
+            },
+            _ => panic!("bad children!"),
+        }
+    }
+}
+
+#[derive(Clone)]
+struct ARCRWData<'a> {
+    name: &'static str,
+    mark: Cell<u32>,
+    children: (Option<&'a ARCRW<'a>>, Option<&'a ARCRW<'a>>),
+}
+
+#[derive(Clone)]
+struct ARCRW<'a>(Arc<RwLock<ARCRWData<'a>>>);
+
+impl<'a> Named for ARCRW<'a> {
+    fn new(name: &'static str) -> Self {
+        ARCRW(Arc::new(RwLock::new(ARCRWData {
+            name: name, mark: Cell::new(0), children: (None, None), })))
+    }
+    fn name(&self) -> &str { self.0.read().unwrap().name }
+}
+
+impl<'a> Marked<u32> for ARCRW<'a> {
+    fn mark(&self) -> u32 { self.0.read().unwrap().mark.get() }
+    fn set_mark(&self, mark: u32) { self.0.read().unwrap().mark.set(mark); }
+}
+
+impl<'a> Children<'a> for ARCRW<'a> {
+    fn count_children(&self) -> usize { 2 }
+    fn descend_one_child<C>(&self, context: &mut C, index: usize)
+        where C: Context + PrePost<Self>, Self: Sized
+    {
+        let children = &self.0.read().unwrap().children;
+        match index {
+            0 => if let Some(ref child) = children.0 {
+                child.descend_into_self(context);
+            },
+            1 => if let Some(ref child) = children.1 {
+                child.descend_into_self(context);
+            },
+            _ => panic!("bad children!"),
+        }
+    }
+}
 
 trait Context {
+    fn next_index(&mut self, len: usize) -> usize;
     fn should_act(&self) -> bool;
     fn increase_visited(&mut self);
     fn increase_skipped(&mut self);
@@ -565,9 +938,17 @@ trait PrePost<T> {
 }
 
 trait Children<'a> {
-    fn for_each_child<C>(&self, context: &mut C)
+    fn count_children(&self) -> usize;
+    fn descend_one_child<C>(&self, context: &mut C, index: usize)
         where C: Context + PrePost<Self>, Self: Sized;
 
+    fn next_child<C>(&self, context: &mut C)
+        where C: Context + PrePost<Self>, Self: Sized
+    {
+        let index = context.next_index(self.count_children());
+        self.descend_one_child(context, index);
+    }
+
     fn descend_into_self<C>(&self, context: &mut C)
         where C: Context + PrePost<Self>, Self: Sized
     {
@@ -575,7 +956,7 @@ fn descend_into_self<C>(&self, context: &mut C)
         if context.should_act() {
             context.increase_visited();
             context.increase_depth();
-            self.for_each_child(context);
+            self.next_child(context);
             context.decrease_depth();
         } else {
             context.hit_limit(self);
@@ -594,51 +975,73 @@ fn descend<'b, C>(&self, c: &Cell<Option<&'b Self>>, context: &mut C)
 }
 
 impl<'a> Children<'a> for S<'a> {
-    fn for_each_child<C>(&self, context: &mut C)
-        where C: Context + PrePost<S<'a>>
+    fn count_children(&self) -> usize { 1 }
+    fn descend_one_child<C>(&self, context: &mut C, _: usize)
+        where C: Context + PrePost<Self>, Self: Sized {
+            self.descend(&self.next, context);
+        }
+}
+
+impl<'a> Children<'a> for S2<'a> {
+    fn count_children(&self) -> usize { 2 }
+    fn descend_one_child<C>(&self, context: &mut C, index: usize)
+        where C: Context + PrePost<Self>, Self: Sized
     {
-        self.descend(&self.next, context);
+        let children = self.next.get();
+        let child = match index {
+            0 => if let Some(child) = children.0 { child } else { return; },
+            1 => if let Some(child) = children.1 { child } else { return; },
+            _ => panic!("bad children"),
+        };
+        // println!("S2 {} descending into child {} at index {}", self.name, child.name, index);
+        child.descend_into_self(context);
     }
 }
 
 impl<'a> Children<'a> for V<'a> {
-    fn for_each_child<C>(&self, context: &mut C)
-        where C: Context + PrePost<V<'a>>
+    fn count_children(&self) -> usize { self.contents.len() }
+    fn descend_one_child<C>(&self, context: &mut C, index: usize)
+        where C: Context + PrePost<Self>, Self: Sized
     {
-        for r in &self.contents {
-            self.descend(r, context);
+        if let Some(child) = self.contents[index].get() {
+            child.descend_into_self(context);
         }
     }
 }
 
 impl<'a> Children<'a> for H<'a> {
-    fn for_each_child<C>(&self, context: &mut C)
-        where C: Context + PrePost<H<'a>>
+    fn count_children(&self) -> usize { 1 }
+    fn descend_one_child<C>(&self, context: &mut C, _: usize)
+        where C: Context + PrePost<Self>, Self: Sized
     {
         self.descend(&self.next, context);
     }
 }
 
 impl<'a> Children<'a> for HM<'a> {
-    fn for_each_child<C>(&self, context: &mut C)
-        where C: Context + PrePost<HM<'a>>
+    fn count_children(&self) -> usize {
+        if let Some(m) = self.contents.get() { 2 * m.iter().count() } else { 0 }
+    }
+    fn descend_one_child<C>(&self, context: &mut C, index: usize)
+        where C: Context + PrePost<Self>, Self: Sized
     {
         if let Some(ref hm) = self.contents.get() {
-            for (k, v) in hm.iter() {
-                for r in &[k, v] {
-                    r.descend_into_self(context);
-                }
+            for (k, v) in hm.iter().nth(index / 2) {
+                [k, v][index % 2].descend_into_self(context);
             }
         }
     }
 }
 
 impl<'a> Children<'a> for VD<'a> {
-    fn for_each_child<C>(&self, context: &mut C)
-        where C: Context + PrePost<VD<'a>>
+    fn count_children(&self) -> usize {
+        if let Some(d) = self.contents.get() { d.iter().count() } else { 0 }
+    }
+    fn descend_one_child<C>(&self, context: &mut C, index: usize)
+        where C: Context + PrePost<Self>, Self: Sized
     {
         if let Some(ref vd) = self.contents.get() {
-            for r in vd.iter() {
+            for r in vd.iter().nth(index) {
                 r.descend_into_self(context);
             }
         }
@@ -646,11 +1049,14 @@ fn for_each_child<C>(&self, context: &mut C)
 }
 
 impl<'a> Children<'a> for VM<'a> {
-    fn for_each_child<C>(&self, context: &mut C)
+    fn count_children(&self) -> usize {
+        if let Some(m) = self.contents.get() { m.iter().count() } else { 0 }
+    }
+    fn descend_one_child<C>(&self, context: &mut C, index: usize)
         where C: Context + PrePost<VM<'a>>
     {
         if let Some(ref vd) = self.contents.get() {
-            for (_idx, r) in vd.iter() {
+            for (_idx, r) in vd.iter().nth(index) {
                 r.descend_into_self(context);
             }
         }
@@ -658,11 +1064,14 @@ fn for_each_child<C>(&self, context: &mut C)
 }
 
 impl<'a> Children<'a> for LL<'a> {
-    fn for_each_child<C>(&self, context: &mut C)
+    fn count_children(&self) -> usize {
+        if let Some(l) = self.contents.get() { l.iter().count() } else { 0 }
+    }
+    fn descend_one_child<C>(&self, context: &mut C, index: usize)
         where C: Context + PrePost<LL<'a>>
     {
         if let Some(ref ll) = self.contents.get() {
-            for r in ll.iter() {
+            for r in ll.iter().nth(index) {
                 r.descend_into_self(context);
             }
         }
@@ -670,11 +1079,14 @@ fn for_each_child<C>(&self, context: &mut C)
 }
 
 impl<'a> Children<'a> for BH<'a> {
-    fn for_each_child<C>(&self, context: &mut C)
+    fn count_children(&self) -> usize {
+        if let Some(h) = self.contents.get() { h.iter().count() } else { 0 }
+    }
+    fn descend_one_child<C>(&self, context: &mut C, index: usize)
         where C: Context + PrePost<BH<'a>>
     {
         if let Some(ref bh) = self.contents.get() {
-            for r in bh.iter() {
+            for r in bh.iter().nth(index) {
                 r.descend_into_self(context);
             }
         }
@@ -682,25 +1094,29 @@ fn for_each_child<C>(&self, context: &mut C)
 }
 
 impl<'a> Children<'a> for BTM<'a> {
-    fn for_each_child<C>(&self, context: &mut C)
+    fn count_children(&self) -> usize {
+        if let Some(m) = self.contents.get() { 2 * m.iter().count() } else { 0 }
+    }
+    fn descend_one_child<C>(&self, context: &mut C, index: usize)
         where C: Context + PrePost<BTM<'a>>
     {
         if let Some(ref bh) = self.contents.get() {
-            for (k, v) in bh.iter() {
-                for r in &[k, v] {
-                    r.descend_into_self(context);
-                }
+            for (k, v) in bh.iter().nth(index / 2) {
+                [k, v][index % 2].descend_into_self(context);
             }
         }
     }
 }
 
 impl<'a> Children<'a> for BTS<'a> {
-    fn for_each_child<C>(&self, context: &mut C)
+    fn count_children(&self) -> usize {
+        if let Some(s) = self.contents.get() { s.iter().count() } else { 0 }
+    }
+    fn descend_one_child<C>(&self, context: &mut C, index: usize)
         where C: Context + PrePost<BTS<'a>>
     {
         if let Some(ref bh) = self.contents.get() {
-            for r in bh.iter() {
+            for r in bh.iter().nth(index) {
                 r.descend_into_self(context);
             }
         }
@@ -716,9 +1132,27 @@ struct ContextData {
     skipped: usize,
     curr_mark: u32,
     saw_prev_marked: bool,
+    control_bits: u64,
 }
 
 impl Context for ContextData {
+    fn next_index(&mut self, len: usize) -> usize {
+        if len < 2 { return 0; }
+        let mut pow2 = len.next_power_of_two();
+        let _pow2_orig = pow2;
+        let mut idx = 0;
+        let mut bits = self.control_bits;
+        while pow2 > 1 {
+            idx = (idx << 1) | (bits & 1) as usize;
+            bits = bits >> 1;
+            pow2 = pow2 >> 1;
+        }
+        idx = idx % len;
+        // println!("next_index({} [{:b}]) says {}, pre(bits): {:b} post(bits): {:b}",
+        //          len, _pow2_orig, idx, self.control_bits, bits);
+        self.control_bits = bits;
+        return idx;
+    }
     fn should_act(&self) -> bool {
         self.curr_depth < self.max_depth && self.visited < self.max_visits
     }