leastUpperBound :: Index -> B.ByteString -> Maybe Int
leastUpperBound index key =
  if lowerBound > upperBound
     then Nothing
     else go indexBounds
  where
    indexBounds@(lowerBound, upperBound) = bounds index

    go (lower, upper)
      -- Standard binary search. Keep in mind the bounds are
      -- inclusive.
      | key == this = Just mid
      | key < this && mid /= lower = go (lower, mid - 1)
      | key > this && mid /= upper = go (mid + 1, upper)

      -- We failed to descend (and thus to find our exact
      -- value). `lower' and `upper' are individually either a bounds
      -- on our search key, or they are the extremes of the index
      -- values.
      --
      -- Thus to find our least upper bound:
      --
      --   If the key is greater than our current value and we are not
      --   at the table extreme, choose our current upper bound.
      | key > this && mid /= upperBound = Just $ mid + 1

      --   If the key is smaller than our current value, select our
      --   current value (the next value down either does not exist or
      --   is smaller than our key by implication of the bounds)
      | key < this = Just mid

      -- Otherwise we fail our search. This happens if the largest
      -- value in the table is smaller than our search key.
      | otherwise = Nothing
        where
          mid = lower + (upper - lower) `div` 2
          (this, off, _) = index!mid
leastUpperBound :: Index -> B.ByteString -> Maybe Int
leastUpperBound index key =
  if lowerBound > upperBound
     then Nothing
     else go indexBounds
  where
    indexBounds@(lowerBound, upperBound) = bounds index

    go (lower, upper)
      -- Standard binary search. Keep in mind the bounds are
      -- inclusive.
      | key == this = Just mid
      | key < this && mid /= lower = go (lower, mid - 1)
      | key > this && mid /= upper = go (mid + 1, upper)

      -- We failed to descend (and thus to find our exact
      -- value). `lower' and `upper' are individually either a bounds
      -- on our search key, or they are the extremes of the index
      -- values.
      --
      -- Thus to find our least upper bound:
      --
      --   If the key is greater than our current value and we are not
      --   at the table extreme, choose our current upper bound.
      | key > this && mid /= upperBound = Just $ mid + 1

      --   If the key is smaller than our current value, select our
      --   current value (the next value down either does not exist or
      --   is smaller than our key by implication of the bounds)
      | key < this = Just mid

      -- Otherwise we fail our search. This happens if the largest
      -- value in the table is smaller than our search key.
      | otherwise = Nothing
        where
          mid = lower + (upper - lower) `div` 2
          (this, off, _) = index!mid
leastUpperBound index key =
  if lowerBound > upperBound
     then Nothing
     else go indexBounds
  where
    indexBounds@(lowerBound, upperBound) = bounds index

    go (lower, upper)
      -- Standard binary search. Keep in mind the bounds are
      -- inclusive.
      | key == this = Just mid
      | key < this && mid /= lower = go (lower, mid - 1)
      | key > this && mid /= upper = go (mid + 1, upper)

      -- We failed to descend (and thus to find our exact
      -- value). `lower' and `upper' are individually either a bounds
      -- on our search key, or they are the extremes of the index
      -- values.
      --
      -- Thus to find our least upper bound:
      --
      --   If the key is greater than our current value and we are not
      --   at the table extreme, choose our current upper bound.
      | key > this && mid /= upperBound = Just $ mid + 1

      --   If the key is smaller than our current value, select our
      --   current value (the next value down either does not exist or
      --   is smaller than our key by implication of the bounds)
      | key < this = Just mid

      -- Otherwise we fail our search. This happens if the largest
      -- value in the table is smaller than our search key.
      | otherwise = Nothing
        where
          mid = lower + (upper - lower) `div` 2
          (this, off, _) = index!mid