x/tools/container/intsets: add LowerBound

Fixes golang/go#21310.

Change-Id: Id3f23a66b9889a5087c1f83e7d672d14c41a59e3
Reviewed-on: https://go-review.googlesource.com/53432
Reviewed-by: Alan Donovan <adonovan@google.com>
diff --git a/container/intsets/sparse.go b/container/intsets/sparse.go
index abe172d..5db01c1 100644
--- a/container/intsets/sparse.go
+++ b/container/intsets/sparse.go
@@ -170,6 +170,26 @@
 	panic("BUG: empty block")
 }
 
+// lowerBound returns the smallest element of the block that is greater than or
+// equal to the element corresponding to the ith bit. If there is no such
+// element, the second return value is false.
+func (b *block) lowerBound(i uint) (int, bool) {
+	w := i / bitsPerWord
+	bit := i % bitsPerWord
+
+	if val := b.bits[w] >> bit; val != 0 {
+		return b.offset + int(i) + ntz(val), true
+	}
+
+	for w++; w < wordsPerBlock; w++ {
+		if val := b.bits[w]; val != 0 {
+			return b.offset + int(w*bitsPerWord) + ntz(val), true
+		}
+	}
+
+	return 0, false
+}
+
 // forEach calls f for each element of block b.
 // f must not mutate b's enclosing Sparse.
 func (b *block) forEach(f func(int)) {
@@ -280,8 +300,26 @@
 	return s.root.min(false)
 }
 
+// LowerBound returns the smallest element >= x, or MaxInt if there is no such
+// element.
+func (s *Sparse) LowerBound(x int) int {
+	offset, i := offsetAndBitIndex(x)
+	for b := s.first(); b != &none; b = s.next(b) {
+		if b.offset > offset {
+			return b.min(false)
+		}
+		if b.offset == offset {
+			if y, ok := b.lowerBound(i); ok {
+				return y
+			}
+		}
+	}
+	return MaxInt
+}
+
 // block returns the block that would contain offset,
 // or nil if s contains no such block.
+// Precondition: offset is a multiple of bitsPerBlock.
 func (s *Sparse) block(offset int) *block {
 	for b := s.first(); b != &none && b.offset <= offset; b = s.next(b) {
 		if b.offset == offset {
diff --git a/container/intsets/sparse_test.go b/container/intsets/sparse_test.go
index d9d4036..e3ef9d3 100644
--- a/container/intsets/sparse_test.go
+++ b/container/intsets/sparse_test.go
@@ -275,11 +275,30 @@
 	}
 }
 
+func TestLowerBound(t *testing.T) {
+	// Use random sets of sizes from 0 to about 4000.
+	prng := rand.New(rand.NewSource(0))
+	for i := uint(0); i < 12; i++ {
+		x := randomPset(prng, 1<<i)
+		for j := 0; j < 10000; j++ {
+			found := intsets.MaxInt
+			for e := range x.hash {
+				if e >= j && e < found {
+					found = e
+				}
+			}
+			if res := x.bits.LowerBound(j); res != found {
+				t.Errorf("%s: LowerBound(%d)=%d, expected %d", &x.bits, j, res, found)
+			}
+		}
+	}
+}
+
 // TestSetOperations exercises classic set operations: ∩ , ∪, \.
 func TestSetOperations(t *testing.T) {
 	prng := rand.New(rand.NewSource(0))
 
-	// Use random sets of sizes from 0 to about 1000.
+	// Use random sets of sizes from 0 to about 4000.
 	// For each operator, we test variations such as
 	// Z.op(X, Y), Z.op(X, Z) and Z.op(Z, Y) to exercise
 	// the degenerate cases of each method implementation.