Browse Source

Eliminate bound checks from the shortcut stacks safely.

- Add the invariant that `lv < LEVELS` to the `Level` newtype.
- Move `Level` to a seperate module, `lv`.
- Make the lookback represent nodes not shortcuts, in order to make
  `remove` work.
- Rename `res` variables to `ret`.
- Improve documentation.
- Add log message to the level generator.
- Fix various off-by-one errors.
ticki 8 years ago
parent
commit
359c6d6f93
9 changed files with 312 additions and 151 deletions
  1. 2 2
      src/allocator.rs
  2. 2 2
      src/arena.rs
  3. 151 0
      src/bk/lv.rs
  4. 1 0
      src/bk/mod.rs
  5. 9 4
      src/bk/node.rs
  6. 2 2
      src/bk/pool.rs
  7. 142 101
      src/bk/seek.rs
  8. 1 38
      src/bk/shortcut.rs
  9. 2 2
      src/fail.rs

+ 2 - 2
src/allocator.rs

@@ -47,7 +47,7 @@ macro_rules! get_allocator {
         {
             THREAD_ALLOCATOR.with(|thread_alloc| {
                 if let Some(mut thread_alloc_original) = thread_alloc.replace(None) {
-                    let res = {
+                    let ret = {
                         // Call the closure involved.
                         let $v = thread_alloc_original.get();
                         $b
@@ -56,7 +56,7 @@ macro_rules! get_allocator {
                     // Put back the original allocator.
                     thread_alloc.replace(Some(thread_alloc_original));
 
-                    res
+                    ret
                 } else {
                     // The local allocator seems to have been deinitialized, for this reason we fallback to
                     // the global allocator.

+ 2 - 2
src/arena.rs

@@ -30,7 +30,7 @@ impl PointerList {
     fn pop(&mut self) -> Option<Pointer<u8>> {
         if let Some(head) = self.head {
             // Get the head pointer.
-            let res = head.clone().cast();
+            let ret = head.clone().cast();
 
             unsafe {
                 // LAST AUDIT: 2016-08-24 (Ticki).
@@ -40,7 +40,7 @@ impl PointerList {
                 *self = ptr::read(*head);
             }
 
-            Some(res)
+            Some(ret)
         } else {
             // The head is `None`, thus the list is empty.
             None

+ 151 - 0
src/bk/lv.rs

@@ -0,0 +1,151 @@
+use core::ops;
+
+use random;
+
+// TODO: Tweak.
+// TODO: Move to shim.
+const LEVELS: usize = 8;
+
+/// A "level".
+///
+/// A level represents a layer of the stack of lists in the skip list. In particular, each node has
+/// some number of "shortcuts", which are ways to skip to a new node. The lowest (and densest)
+/// shortcut is level 0.
+///
+/// This is bounded by the maximal height. This invariant allows avoiding bound checks in the array
+/// newtype.
+// TODO: Link `Array` above.
+#[derive(Copy, Clone, PartialEq, Eq)]
+pub struct Level(usize);
+
+impl Level {
+    /// Generate a level.
+    ///
+    /// This is equivalent to making some specified number of coinflips and count until you get
+    /// heads and saturate if none are made.
+    ///
+    /// We make use of bit hacks to speed this process up such that only one random state update is
+    /// needed.
+    ///
+    /// `None` ($$p = 0.5$$) represent that no level is generated and that the node in question
+    /// should hold no shortcuts.
+    #[inline]
+    pub fn generate() -> Option<Level> {
+        // Naturally, the ffz conforms to our wanted probability distribution, $$p(x) = 2^{-x}$$. We
+        // apply a bit mask to saturate when the ffz is greater than `LEVELS`.
+        let height = (random::get() & (1 << LEVELS - 1)).trailing_zeros();
+
+        // TODO: Strictly speaking not a node...
+        log!("DEBUG", "Generated node with height {}/{}.", height, LEVELS);
+
+        // TODO: Find a way to eliminate this branch.
+        if rand == 0 {
+            None
+        } else {
+            Some(height - 1)
+        }
+    }
+
+    pub fn above(self) -> Option<Level> {
+        // TODO: Find a way to eliminate this branch.
+        if self == Level::max() {
+            None
+        } else {
+            Some(Level(self.0 + 1))
+        }
+    }
+
+    #[inline]
+    pub fn min() -> Level {
+        Level(0)
+    }
+
+    #[inline]
+    pub fn max() -> Level {
+        Level(LEVELS - 1)
+    }
+
+    #[inline]
+    pub unsafe fn from_usize(lv: usize) -> Level {
+        debug_assert!(lv < LEVELS, "Level is out of bounds.");
+
+        Level(lv)
+    }
+}
+
+impl Into<usize> for Level {
+    fn into(self) -> usize {
+        self.0
+    }
+}
+
+pub struct Iter {
+    lv: usize,
+    to: usize,
+}
+
+impl Iter {
+    #[inline]
+    pub fn start_at(lv: Level) -> Iter {
+        Iter {
+            lv: lv.0,
+            to: Level::max().0,
+        }
+    }
+
+    #[inline]
+    pub fn all() -> Iter {
+        Iter::start_at(Level::min())
+    }
+
+    /// Create an iterator over all the layers above the bottom layer.
+    #[inline]
+    pub fn non_bottom() -> Iter {
+        Iter::start_at(Level(1))
+    }
+
+    pub fn to(mut self, to: Level) -> Iter {
+        self.to = to;
+        self
+    }
+}
+
+impl Iterator for LevelIter {
+    type Item = Level;
+
+    fn next(&mut self) -> Option<Level> {
+        if self.lv <= self.to {
+            let ret = self.n;
+
+            // Increment the counter.
+            self.lv = ret + 1;
+
+            Some(Level(ret))
+        } else {
+            // We reached the last element in the iterator.
+            None
+        }
+    }
+}
+
+/// An array that has the size of the number levels.
+///
+/// This is used to prevent bound checks, since the bound is encoded into the indexing type, and
+/// thus statically ensured.
+pub struct Array<T> {
+    inner: [T; LEVELS],
+}
+
+impl<T> ops::Index<Level> for Array {
+    type Output = T;
+
+    fn index(&self, lv: Level) -> &T {
+        self.inner.get_unchecked(lv.0)
+    }
+}
+
+impl<T> ops::IndexMut<Level> for Array {
+    fn index_mut(&mut self, lv: Level) -> &mut T {
+        self.inner.get_unchecked_mut(lv.0)
+    }
+}

+ 1 - 0
src/bk/mod.rs

@@ -23,6 +23,7 @@
 ///       |    __    \__.
 ///       |_!_|  |_!_|
 
+mod lv;
 mod node;
 mod seek;
 mod shortcut;

+ 9 - 4
src/bk/node.rs

@@ -33,7 +33,12 @@ struct Node {
     ///
     /// If we assume our node is `[6]`, the stack would contain shotcuts to 7, 7, and 8, in that
     /// order. The rest would simply be null pointers with fat value 0.
-    shortcuts: [Shortcut; LEVELS],
+    ///
+    /// # Height
+    ///
+    /// The index of the highest null shortcut (or, if none, the length of the array) is called the
+    /// height of the node.
+    shortcuts: lv::Array<Shortcut>,
 }
 
 impl Node {
@@ -72,7 +77,7 @@ impl Node {
     /// This will simply traverse the layer below (given in the form of an iterator) and find the
     /// maximal fat value. The result is guaranteed to be equal to or greater than
     /// `self.block.size()`.
-    fn calculate_fat_value<I>(&self, lv: shortcut::Level, below: I) -> block::Size
+    fn calculate_fat_value<I>(&self, lv: lv::Level, below: I) -> block::Size
         where I: Iterator<Item = &Node> {
         // We start at the block's size.
         let mut new_fat = 0;
@@ -154,7 +159,7 @@ impl Node {
                     fat value does not match the calculated fat value.");
 
             // Check the fat values of the non bottom level.
-            for lv in shortcut::level_iter().skip(1) {
+            for lv in lv::level_iter().skip(1) {
                 assert!(self.shortcuts[lv.into()].fat == self.calculate_fat_value_non_bottom(lv), "The \
                         bottom layer's fat value does not match the calculated fat value.");
             }
@@ -162,7 +167,7 @@ impl Node {
             // Check that the shortcut refers to a node with appropriate (equal to or greater)
             // height.
             // FIXME: Fold this loop to the one above.
-            for lv in shortcut::level_iter() {
+            for lv in lv::level_iter() {
                 assert!(!self.shortcuts[lv.into()].next.shortcuts[lv.into()].is_null(), "Shortcut \
                         points to a node with a lower height. Is this a dangling pointer?");
             }

+ 2 - 2
src/bk/pool.rs

@@ -28,12 +28,12 @@ impl Pool {
         //     # --> [1] --> [5] --> [6] --> [7] --> [8] --> [9] --> [10] --> NIL
 
         // Start at the highest (least dense) level.
-        let mut iter = self.head.follow_shortcut(shortcut::Level::max());
+        let mut iter = self.head.follow_shortcut(lv::Level::max());
         // Go forward until we overshoot.
         while let Some(shortcut_taken) = iter.take_while(|x| x < block).last() {
 
             // Decrement the level.
-            let shortcut::Level(lv) = iter.decrement_level();
+            let lv::Level(lv) = iter.decrement_level();
             log!(INTERNAL, "Going from level {} to level {}.", lv, lv - 1);
 
             // Update the back look respectively.

+ 142 - 101
src/bk/seek.rs

@@ -2,23 +2,21 @@
 ///
 /// Seek represents the a found node ("needle") and backtracking information ("lookback").
 struct Seek<'a> {
-    /// The last shortcut below our target for each level.
+    /// The last node below our target for each level.
     ///
     /// This is used for insertions and other backtracking.
     ///
     /// The lower indexes are the denser layers.
     ///
-    /// An entry of this array is called a "skip", because it _skips_ over the node..
-    ///
     /// # An important note!
     ///
-    /// It is crucial that the backlook is pointers to shortcuts _before_ the target, not shortcuts
-    /// starting at the target.
+    /// It is crucial that the backlook is pointers to nodes _before_ the target, not the target
+    /// node itself.
     ///
     /// # Example
     ///
     /// Consider if we search for 8. Now, we move on until we overshoot. The node before the
-    /// overshot is a skip (marked with curly braces).
+    /// overshot is a lookback entry (marked with curly braces).
     ///
     ///     ...
     ///     2      # ---------------------> {6} ---------------------> [9] -------------> NIL
@@ -28,7 +26,7 @@ struct Seek<'a> {
     ///
     /// So, the lookback of this particular seek is `[6, 7, 7, ...]`.
     // FIXME: Find a more rustic way than raw pointers.
-    lookback: [Pointer<Shortcuts>; LEVELS.0],
+    lookback: lv::Array<Pointer<Node>>,
     /// A pointer to a pointer to the found node.
     ///
     /// This is the node equal to or less than the target. The two layers of pointers are there to
@@ -39,14 +37,14 @@ struct Seek<'a> {
 impl<'a> Seek<'a> {
     /// Update the fat values of this seek to be higher than or equal to some new block size.  .
     ///
-    /// This will simply run over and update the fat values of shortcuts above some level with a
-    /// new size.
+    /// This will simply run over and update the fat values of shortcuts of some level and above
+    /// with a new size.
     ///
     /// Note that this cannot be used to remove a block, since that might decrease some fat values.
     #[inline]
-    fn increase_fat(&mut self, size: block::Size, above: shortcut::Level) {
-        // Go from the densest layer and up, to update the fat node values.
-        for i in &mut self.lookback[above..] {
+    fn increase_fat(&mut self, size: block::Size, from: lv::Level) {
+        // Start after `above` and go up, to update the fat node values.
+        for i in &mut self.skips_from(above) {
             if !i.increase_fat(size) {
                 // Short-circuit for performance reasons.
                 break;
@@ -54,6 +52,27 @@ impl<'a> Seek<'a> {
         }
     }
 
+    /// Get the `lv`'th "skip" of this seek.
+    ///
+    /// The $$n$$'th shortcut of the $$n$$'th entry of the lookback is referred to as the $$n$$'th
+    /// "skip", because it _skips_ over the target node.
+    fn get_skip(&mut self, lv: lv::Level) -> &mut Shortcut {
+        &mut self.lookback[lv].shorcuts[lv]
+    }
+
+    /// Create an iterator over all of the skips of this seek.
+    fn skips(&mut self) -> impl Iterator<Item = &mut Shortcut> {
+        self.skips_from(Level(0))
+    }
+
+    /// Create an iterator over the skips of this seek starting at some level.
+    fn skips_from(&mut self, lv: lv::Level) -> impl Iterator<Item = &mut Shortcut> {
+        Skips {
+            seek: self,
+            n: lv::Iter::start_at(lv),
+        }
+    }
+
     fn put(&mut self, block: Block, arena: &mut Arena<Node>) {
         if self.node.block.merge_right(block).is_ok() {
             // Merge suceeded:
@@ -63,7 +82,7 @@ impl<'a> Seek<'a> {
             //     [==self=============] [==rest==]
 
             // Update the fat values.
-            self.increase_fat(self.node.block.size(), 0);
+            self.increase_fat(self.node.block.size(), Level::min());
 
             // If our configuration now looks like:
             //     [==self=============][==rest==]
@@ -81,13 +100,15 @@ impl<'a> Seek<'a> {
             //     [==self==] [==right=============]
 
             // Update the fat values.
-            self.increase_fat(block.size(), 0);
+            self.increase_fat(block.size(), Level::min());
 
             // In case that our new configuration looks like:
             //     [==self==][==right=============]
             // We need to merge the former block right:
             self.try_merge_right(arena);
         } else {
+            // We were unabled to merge it with a preexisting block, so we need to insert it
+            // instead.
             self.insert_no_merge(block, arena);
         }
     }
@@ -98,14 +119,14 @@ impl<'a> Seek<'a> {
             // block will be left right to the node. As such the fat node's size is greater than or
             // equal to the new, merged node's size. So we need not full reevaluation of the fat
             // values, instead we can simply climb upwards and max the new size together.
-            for (i, shortcut) in self.lookback.iter().zip(i.next.shortcuts) {
+            for (i, shortcut) in self.skips().zip(i.next.shortcuts) {
                 // Update the shortcut to skip over the next shortcut. Note that this statements
                 // makes it impossible to shortcut like in `insert`.
                 i.next = shortcut.next;
                 // Update the fat value to make sure it is greater or equal to the new block size.
                 // Note that we do not short-circuit -- on purpose -- due to the above statement
                 // being needed for correctness.
-                i.increase_fat(self.node.block.size(), block::Size(0));
+                i.increase_fat(self.node.block.size(), Level::min());
 
                 // TODO: Consider breaking this loop into two loops to avoid too many fat value
                 //       updates.
@@ -132,11 +153,11 @@ impl<'a> Seek<'a> {
     //     [self.lookback[lv]] -f-> [self.lookback[lv].next]
     // To:
     //     [self.lookback[lv]] -f-> [self.node] -0-> [old self.lookback[lv].next]
-    fn insert_shortcut(&mut self, lv: shortcut::Level) -> Pointer<Shortcut> {
+    fn insert_shortcut(&mut self, lv: lv::Level) -> Pointer<Shortcut> {
         debug_assert!(self.node.shortcuts[lv].is_null(), "Overwriting a non-null shortcut.");
 
         // Make the old shortcut point to `self.node`.
-        let old_next = mem::replace(&mut self.lookback[lv].next, Some(self.node));
+        let old_next = mem::replace(&mut self.get_skip(lv).next, Some(self.node));
         // Update the shortcut of our node to point to the old shortcut's next node.
         self.node.shortcuts[lv] = Shortcut {
             next: old_next,
@@ -158,9 +179,6 @@ impl<'a> Seek<'a> {
             // Check that we're inserting at a fitting position, such that the list is kept sorted.
             debug_assert!(self.node.block < block, "Inserting at a wrong position.");
 
-            // Generate the maximum level of the new node's shortcuts.
-            let height = shortcut::Level::generate();
-
             // Put the old node behind the new node holding block.
             seek.node.insert(arena.alloc(Node {
                 block: block,
@@ -169,12 +187,13 @@ impl<'a> Seek<'a> {
                 next: None,
             }));
 
-            // If we actually have a bottom layer (i.e. the generated level is higher than zero),
-            // we obviously need to update its fat values based on the main list.
-            // FIXME: This code is copied from the loop below. Find a way to avoid repeating.
-            if height > shortcut::Level(0) {
+            // Generate the maximum level of the new node's shortcuts.
+            if let Some(max_lv) = lv::Level::generate() {
+                // If we actually have a bottom layer (i.e. the generated level is higher than zero),
+                // we obviously need to update its fat values based on the main list.
+                // FIXME: This code is copied from the loop below. Find a way to avoid repeating.
                 // Place the node into the bottom shortcut.
-                self.insert_shortcut(shortcut::Level(0));
+                self.insert_shortcut(lv::Level::min());
 
                 // For details how this works, see the loop below. This is really just taken from
                 // the iteration from that to reflect the special structure of the block list.
@@ -182,7 +201,7 @@ impl<'a> Seek<'a> {
                 // Calculate the fat value of the bottom layer.
                 let new_fat = seek.node.calculate_fat_value_bottom();
 
-                let skip = &mut seek.lookback[0];
+                let skip = &mut seek.get_skip(lv::Level::min());
                 if new_fat == skip.fat {
                     if let Some(next) = skip.next {
                         next.fat = next.calculate_fat_value_bottom();
@@ -190,80 +209,83 @@ impl<'a> Seek<'a> {
                 } else {
                     skip.node.shortcuts[0].increase_fat(mem::replace(&mut skip.fat, new_fat));
                 }
-            }
 
-            // Place new shortcuts up to this level.
-            for lv in shortcut::Level(1)..height {
-                // Place the node inbetween the shortcuts.
-                seek.insert_shortcut(lv);
-
-                // The configuration (at level `lv`) should now look like:
-                //     [seek.node] --> [old self.node] --> [old shortcut]
-
-                // Since we inserted a new shortcut here, we might have invalidated the old fat
-                // value, so we need to recompute the fat value. Fortunately, since we go from
-                // densest to opaquer layer, we can base the fat value on the values of the
-                // previous layer.
-
-                // An example state could look like this: Assume we go from this configuration:
-                //     [a] -y----------> [b] ---> ...
-                //     [a] -x----------> [b] ---> ...
-                //     ...
-                // To this:
-                //     [a] -y'---------> [b] ---> ...
-                //     [a] -p-> [n] -q-> [b] ---> ...
-                //     ...
-                // Here, you cannot express _p_ and _q_ in terms  of _x_ and _y_. Instead, we need
-                // to compute them from the layer below.
-                let new_fat = seek.node.calculate_fat_value_non_bottom(lv);
-
-                // You have been visitied by the silly ferris.
-                //      ()    ()
-                //       \/\/\/
-                //       &_^^_&
-                //       \    /
-                // Fix all bugs in 0.9345 seconds, or you will be stuck doing premature
-                // optimizations forever.
-
-                // Avoid multiple bound checks.
-                let skip = &mut seek.lookback[lv];
-                // The shortcut behind the updated one might be invalidated as well. We use a nifty
-                // trick: If the fat node is not present on one part of the split (defined by the
-                // newly inserted node), it must fall on the other. So, we can shortcut and safely
-                // skip computation of the second part half of the time.
-                if new_fat == skip.fat {
-                    if let Some(next) = skip.next {
-                        // The fat value was left unchanged. This means that we need to recompute the
-                        // next segment's fat value.
-                        next.fat = next.calculate_fat_value_non_bottom(lv);
+                // Place new shortcuts up to this level.
+                for lv in lv::Iter::non_bottom().to(max_lv) {
+                    // Place the node inbetween the shortcuts.
+                    seek.insert_shortcut(lv);
+
+                    // The configuration (at level `lv`) should now look like:
+                    //     [seek.node] --> [old self.node] --> [old shortcut]
+
+                    // Since we inserted a new shortcut here, we might have invalidated the old fat
+                    // value, so we need to recompute the fat value. Fortunately, since we go from
+                    // densest to opaquer layer, we can base the fat value on the values of the
+                    // previous layer.
+
+                    // An example state could look like this: Assume we go from this configuration:
+                    //     [a] -y----------> [b] ---> ...
+                    //     [a] -x----------> [b] ---> ...
+                    //     ...
+                    // To this:
+                    //     [a] -y'---------> [b] ---> ...
+                    //     [a] -p-> [n] -q-> [b] ---> ...
+                    //     ...
+                    // Here, you cannot express _p_ and _q_ in terms  of _x_ and _y_. Instead, we need
+                    // to compute them from the layer below.
+                    let new_fat = seek.node.calculate_fat_value_non_bottom(lv);
+
+                    // You have been visitied by the silly ferris.
+                    //      ()    ()
+                    //       \/\/\/
+                    //       &_^^_&
+                    //       \    /
+                    // Fix all bugs in 0.9345 seconds, or you will be stuck doing premature
+                    // optimizations forever.
+
+                    // Avoid multiple bound checks.
+                    let skip = &mut seek.get_skip(lv);
+                    // The shortcut behind the updated one might be invalidated as well. We use a nifty
+                    // trick: If the fat node is not present on one part of the split (defined by the
+                    // newly inserted node), it must fall on the other. So, we can shortcut and safely
+                    // skip computation of the second part half of the time.
+                    if new_fat == skip.fat {
+                        if let Some(next) = skip.next {
+                            // The fat value was left unchanged. This means that we need to recompute the
+                            // next segment's fat value.
+                            next.fat = next.calculate_fat_value_non_bottom(lv);
+                        }
+
+                        // Since it was unchanged, there is no need for setting the value to what it
+                        // already is!
+                    } else {
+                        // The first segment did not contain the fat node! This means that we know a
+                        // priori that the second segment contains the old fat node, i.e. has either
+                        // the same fat value or the updated node is itself the fat node. So, we
+                        // replace the new fat value and update the next segment with the old one.  As
+                        // an example, suppose the configuration looked like:
+                        //     [a] -f----------> [b]
+                        // And we inserted a new node $x$:
+                        //     [a] -g-> [x] -h-> [b]
+                        // Since the fat node (size $f$) couldn't be found on the left side ($g$) of
+                        // $x$, it must be on the right side ($h ≥ f$). It might not be equal to it,
+                        // because the size of $x$ could be greater than $f$, so we take the maximal of
+                        // $x$ and $f$ and assigns that to $h$. This way we avoid having to iterate
+                        // over all the nodes between $x$ and $b$.
+                        skip.next.unwrap().shortcuts[lv]
+                            .increase_fat(cmp::max(mem::replace(&mut skip.fat, new_fat), seek.node.block.size()));
                     }
+                }
 
-                    // Since it was unchanged, there is no need for setting the value to what it
-                    // already is!
-                } else {
-                    // The first segment did not contain the fat node! This means that we know a
-                    // priori that the second segment contains the old fat node, i.e. has either
-                    // the same fat value or the updated node is itself the fat node. So, we
-                    // replace the new fat value and update the next segment with the old one.  As
-                    // an example, suppose the configuration looked like:
-                    //     [a] -f----------> [b]
-                    // And we inserted a new node $x$:
-                    //     [a] -g-> [x] -h-> [b]
-                    // Since the fat node (size $f$) couldn't be found on the left side ($g$) of
-                    // $x$, it must be on the right side ($h ≥ f$). It might not be equal to it,
-                    // because the size of $x$ could be greater than $f$, so we take the maximal of
-                    // $x$ and $f$ and assigns that to $h$. This way we avoid having to iterate
-                    // over all the nodes between $x$ and $b$.
-                    skip.next.unwrap().shortcuts[lv].increase_fat(mem::replace(&mut skip.fat, new_fat), seek.node.block.size());
+                // The levels above the inserted shortcuts need to get there fat value updated, since a
+                // new node was inserted below. Since we only inserted (i.e. added a potentially new
+                // fat node), we simply need to max the old (unupdated) fat values with the new block's
+                // size.
+                if let Some(above) = max_lv.above() {
+                    seek.increase_fat(seek.node.block.size(), above);
                 }
             }
 
-            // The levels above the inserted shortcuts need to get there fat value updated, since a
-            // new node was inserted below. Since we only inserted (i.e. added a potentially new
-            // fat node), we simply need to max the old (unupdated) fat values with the new block's
-            // size.
-            seek.increase_fat(seek.node.block.size(), height);
-
             seek.node.check();
 
             seek
@@ -275,16 +297,16 @@ impl<'a> Seek<'a> {
     fn remove(self) -> Jar<Node> {
         // Remove the shortcuts that skips the target node (exclude the node from the skip of every
         // level). This is in place to make sure there's no dangling pointers after.
-        for (_, lookback) in self.node.shortcuts().zip(self.lookback) {
+        for (_, skip) in self.node.shortcuts().zip(self.skips()) {
             // Jump over the skip's next node (note how the shortcut will never start at
             // `self.node` and hence always be the one we remove here). We can safely unwrap this,
             // because we know that `self.node` is at least of this height, by the zip iterator
             // adapter.
-            lookback.next = lookback.next.unwrap().next;
+            skip.next = skip.next.unwrap().next;
         }
 
         // Update the fat values to reflect the new state.
-        for i in self.lookback {
+        for i in self.skips() {
             if i.fat == self.node.size() {
                 // Recalculate the fat value.
                 let old_fat = i.fat;
@@ -328,11 +350,11 @@ impl<'a> Seek<'a> {
             }
 
             // Make sure that the first skip is overshooting the node as expected.
-            assert!(self.lookback[0].next.and_then(|x| x.block) >= self.node.block, "The first \
+            assert!(self.get_skip(0).next.and_then(|x| x.block) >= self.node.block, "The first \
                     skip is not overshooting the node of the seek.");
 
             // Check the lookback.
-            let mut iter = self.lookback.peekable();
+            let mut iter = self.skips().peekable();
             let mut n = 0;
             loop {
                 let cur = iter.next();
@@ -340,7 +362,7 @@ impl<'a> Seek<'a> {
 
                 if let Some(cur) = cur {
                     // Make sure the shortcut doesn't start at the node (this is done by making
-                    // sure the skip and the n'th shortcut of the current node are distinct).
+                    // sure the skip and the $n$'th shortcut of the current node are distinct).
                     assert!(cur.next != self.node.shortcuts[n].next, "The {}'th skip starts at \
                             the target node.");
 
@@ -364,3 +386,22 @@ impl<'a> Seek<'a> {
         }
     }
 }
+
+struct Skips<'a> {
+    seek: &'a Seek<'a>,
+    levels: lv::Iter,
+}
+
+impl<'a> Iterator for Skips<'a> {
+    type Iter = &'a mut Shortcut;
+
+    fn next(&mut self) -> Option<&'a mut Shortcut> {
+        // Progress the level iterator.
+        if let Some(lv) = self.levels.next() {
+            // Return the skip.
+            Some(self.seek.get_skip(lv))
+        } else {
+            None
+        }
+    }
+}

+ 1 - 38
src/bk/shortcut.rs

@@ -1,43 +1,5 @@
 use block;
 
-// TODO: Tweak.
-// TODO: Move to shim.
-const LEVELS: Level = Level(8);
-
-usize_newtype!(pub Level);
-
-impl Level {
-    /// Generate a skip list level.
-    ///
-    /// This is equivalent to making `LEVELS` coinflips and count until you get heads and saturate to
-    /// `LEVELS` if none is made.
-    ///
-    /// We make use of bit hacks to speed this process up such that only one random state update is
-    /// needed.
-    #[inline]
-    fn generate_level() -> Level {
-        // Naturally, the ffz conforms to our wanted probability distribution, $$p(x) = 2^{-x}$$. We
-        // apply a bit mask to saturate when the ffz is greater than `LEVELS`.
-        (random::get() & (1 << LEVELS - 1)).trailing_zeros()
-    }
-
-    #[inline]
-    fn max() -> Level {
-        LEVELS - Level(1)
-    }
-}
-
-impl Into<usize> for Level {
-    fn into(self) -> usize {
-        self.0
-    }
-}
-
-#[inline]
-fn level_iter() -> impl Iterator<Item = Level> {
-    Level(0)..Level::max()
-}
-
 /// A shortcut (a pointer to a later node and the size of the biggest block it skips).
 ///
 /// A shortcut stores two values: a pointer to the node it skips to, and the size of the "fat
@@ -118,6 +80,7 @@ impl Shortcut {
     ///         4
     ///         |
     ///         2
+    ///
     /// Let $$A$$ be a node with set of children $$C$$, then $$A = \max(C)$$. As such, if I start
     /// in the bottom and iterate upwards, as soon as the value stays unchanged, the rest of the
     /// values won't change either.

+ 2 - 2
src/fail.rs

@@ -73,10 +73,10 @@ pub fn set_thread_oom_handler(handler: fn() -> !) {
 
     THREAD_OOM_HANDLER.with(|thread_oom| {
         // Replace it with the new handler.
-        let res = thread_oom.replace(Some(handler));
+        let old = thread_oom.replace(Some(handler));
 
         // Throw a warning if it overrides another handler.
-        if res.is_some() {
+        if old.is_some() {
             log!(WARNING, "An old thread OOM handler was overriden.");
         }
     });