| // Copyright 2014 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // Package intsets provides Sparse, a compact and fast representation |
| // for sparse sets of int values. |
| // |
| // The time complexity of the operations Len, Insert, Remove and Has |
| // is in O(n) but in practice those methods are faster and more |
| // space-efficient than equivalent operations on sets based on the Go |
| // map type. The IsEmpty, Min, Max, Clear and TakeMin operations |
| // require constant time. |
| // |
| package intsets // import "golang.org/x/tools/container/intsets" |
| |
| // TODO(adonovan): |
| // - Add InsertAll(...int), RemoveAll(...int) |
| // - Add 'bool changed' results for {Intersection,Difference}With too. |
| // |
| // TODO(adonovan): implement Dense, a dense bit vector with a similar API. |
| // The space usage would be proportional to Max(), not Len(), and the |
| // implementation would be based upon big.Int. |
| // |
| // TODO(adonovan): experiment with making the root block indirect (nil |
| // iff IsEmpty). This would reduce the memory usage when empty and |
| // might simplify the aliasing invariants. |
| // |
| // TODO(adonovan): opt: make UnionWith and Difference faster. |
| // These are the hot-spots for go/pointer. |
| |
| import ( |
| "bytes" |
| "fmt" |
| ) |
| |
| // A Sparse is a set of int values. |
| // Sparse operations (even queries) are not concurrency-safe. |
| // |
| // The zero value for Sparse is a valid empty set. |
| // |
| // Sparse sets must be copied using the Copy method, not by assigning |
| // a Sparse value. |
| // |
| type Sparse struct { |
| // An uninitialized Sparse represents an empty set. |
| // An empty set may also be represented by |
| // root.next == root.prev == &root. |
| // In a non-empty set, root.next points to the first block and |
| // root.prev to the last. |
| // root.offset and root.bits are unused. |
| root block |
| } |
| |
| type word uintptr |
| |
| const ( |
| _m = ^word(0) |
| bitsPerWord = 8 << (_m>>8&1 + _m>>16&1 + _m>>32&1) |
| bitsPerBlock = 256 // optimal value for go/pointer solver performance |
| wordsPerBlock = bitsPerBlock / bitsPerWord |
| ) |
| |
| // Limit values of implementation-specific int type. |
| const ( |
| MaxInt = int(^uint(0) >> 1) |
| MinInt = -MaxInt - 1 |
| ) |
| |
| // -- block ------------------------------------------------------------ |
| |
| // A set is represented as a circular doubly-linked list of blocks, |
| // each containing an offset and a bit array of fixed size |
| // bitsPerBlock; the blocks are ordered by increasing offset. |
| // |
| // The set contains an element x iff the block whose offset is x - (x |
| // mod bitsPerBlock) has the bit (x mod bitsPerBlock) set, where mod |
| // is the Euclidean remainder. |
| // |
| // A block may only be empty transiently. |
| // |
| type block struct { |
| offset int // offset mod bitsPerBlock == 0 |
| bits [wordsPerBlock]word // contains at least one set bit |
| next, prev *block // doubly-linked list of blocks |
| } |
| |
| // wordMask returns the word index (in block.bits) |
| // and single-bit mask for the block's ith bit. |
| func wordMask(i uint) (w uint, mask word) { |
| w = i / bitsPerWord |
| mask = 1 << (i % bitsPerWord) |
| return |
| } |
| |
| // insert sets the block b's ith bit and |
| // returns true if it was not already set. |
| // |
| func (b *block) insert(i uint) bool { |
| w, mask := wordMask(i) |
| if b.bits[w]&mask == 0 { |
| b.bits[w] |= mask |
| return true |
| } |
| return false |
| } |
| |
| // remove clears the block's ith bit and |
| // returns true if the bit was previously set. |
| // NB: may leave the block empty. |
| // |
| func (b *block) remove(i uint) bool { |
| w, mask := wordMask(i) |
| if b.bits[w]&mask != 0 { |
| b.bits[w] &^= mask |
| return true |
| } |
| return false |
| } |
| |
| // has reports whether the block's ith bit is set. |
| func (b *block) has(i uint) bool { |
| w, mask := wordMask(i) |
| return b.bits[w]&mask != 0 |
| } |
| |
| // empty reports whether b.len()==0, but more efficiently. |
| func (b *block) empty() bool { |
| for _, w := range b.bits { |
| if w != 0 { |
| return false |
| } |
| } |
| return true |
| } |
| |
| // len returns the number of set bits in block b. |
| func (b *block) len() int { |
| var l int |
| for _, w := range b.bits { |
| l += popcount(w) |
| } |
| return l |
| } |
| |
| // max returns the maximum element of the block. |
| // The block must not be empty. |
| // |
| func (b *block) max() int { |
| bi := b.offset + bitsPerBlock |
| // Decrement bi by number of high zeros in last.bits. |
| for i := len(b.bits) - 1; i >= 0; i-- { |
| if w := b.bits[i]; w != 0 { |
| return bi - nlz(w) - 1 |
| } |
| bi -= bitsPerWord |
| } |
| panic("BUG: empty block") |
| } |
| |
| // min returns the minimum element of the block, |
| // and also removes it if take is set. |
| // The block must not be initially empty. |
| // NB: may leave the block empty. |
| // |
| func (b *block) min(take bool) int { |
| for i, w := range b.bits { |
| if w != 0 { |
| tz := ntz(w) |
| if take { |
| b.bits[i] = w &^ (1 << uint(tz)) |
| } |
| return b.offset + int(i*bitsPerWord) + tz |
| } |
| } |
| panic("BUG: empty block") |
| } |
| |
| // forEach calls f for each element of block b. |
| // f must not mutate b's enclosing Sparse. |
| func (b *block) forEach(f func(int)) { |
| for i, w := range b.bits { |
| offset := b.offset + i*bitsPerWord |
| for bi := 0; w != 0 && bi < bitsPerWord; bi++ { |
| if w&1 != 0 { |
| f(offset) |
| } |
| offset++ |
| w >>= 1 |
| } |
| } |
| } |
| |
| // offsetAndBitIndex returns the offset of the block that would |
| // contain x and the bit index of x within that block. |
| // |
| func offsetAndBitIndex(x int) (int, uint) { |
| mod := x % bitsPerBlock |
| if mod < 0 { |
| // Euclidean (non-negative) remainder |
| mod += bitsPerBlock |
| } |
| return x - mod, uint(mod) |
| } |
| |
| // -- Sparse -------------------------------------------------------------- |
| |
| // start returns the root's next block, which is the root block |
| // (if s.IsEmpty()) or the first true block otherwise. |
| // start has the side effect of ensuring that s is properly |
| // initialized. |
| // |
| func (s *Sparse) start() *block { |
| root := &s.root |
| if root.next == nil { |
| root.next = root |
| root.prev = root |
| } else if root.next.prev != root { |
| // Copying a Sparse x leads to pernicious corruption: the |
| // new Sparse y shares the old linked list, but iteration |
| // on y will never encounter &y.root so it goes into a |
| // loop. Fail fast before this occurs. |
| panic("A Sparse has been copied without (*Sparse).Copy()") |
| } |
| |
| return root.next |
| } |
| |
| // IsEmpty reports whether the set s is empty. |
| func (s *Sparse) IsEmpty() bool { |
| return s.start() == &s.root |
| } |
| |
| // Len returns the number of elements in the set s. |
| func (s *Sparse) Len() int { |
| var l int |
| for b := s.start(); b != &s.root; b = b.next { |
| l += b.len() |
| } |
| return l |
| } |
| |
| // Max returns the maximum element of the set s, or MinInt if s is empty. |
| func (s *Sparse) Max() int { |
| if s.IsEmpty() { |
| return MinInt |
| } |
| return s.root.prev.max() |
| } |
| |
| // Min returns the minimum element of the set s, or MaxInt if s is empty. |
| func (s *Sparse) Min() int { |
| if s.IsEmpty() { |
| return MaxInt |
| } |
| return s.root.next.min(false) |
| } |
| |
| // block returns the block that would contain offset, |
| // or nil if s contains no such block. |
| // |
| func (s *Sparse) block(offset int) *block { |
| b := s.start() |
| for b != &s.root && b.offset <= offset { |
| if b.offset == offset { |
| return b |
| } |
| b = b.next |
| } |
| return nil |
| } |
| |
| // Insert adds x to the set s, and reports whether the set grew. |
| func (s *Sparse) Insert(x int) bool { |
| offset, i := offsetAndBitIndex(x) |
| b := s.start() |
| for b != &s.root && b.offset <= offset { |
| if b.offset == offset { |
| return b.insert(i) |
| } |
| b = b.next |
| } |
| |
| // Insert new block before b. |
| new := &block{offset: offset} |
| new.next = b |
| new.prev = b.prev |
| new.prev.next = new |
| new.next.prev = new |
| return new.insert(i) |
| } |
| |
| func (s *Sparse) removeBlock(b *block) { |
| b.prev.next = b.next |
| b.next.prev = b.prev |
| } |
| |
| // Remove removes x from the set s, and reports whether the set shrank. |
| func (s *Sparse) Remove(x int) bool { |
| offset, i := offsetAndBitIndex(x) |
| if b := s.block(offset); b != nil { |
| if !b.remove(i) { |
| return false |
| } |
| if b.empty() { |
| s.removeBlock(b) |
| } |
| return true |
| } |
| return false |
| } |
| |
| // Clear removes all elements from the set s. |
| func (s *Sparse) Clear() { |
| s.root.next = &s.root |
| s.root.prev = &s.root |
| } |
| |
| // If set s is non-empty, TakeMin sets *p to the minimum element of |
| // the set s, removes that element from the set and returns true. |
| // Otherwise, it returns false and *p is undefined. |
| // |
| // This method may be used for iteration over a worklist like so: |
| // |
| // var x int |
| // for worklist.TakeMin(&x) { use(x) } |
| // |
| func (s *Sparse) TakeMin(p *int) bool { |
| head := s.start() |
| if head == &s.root { |
| return false |
| } |
| *p = head.min(true) |
| if head.empty() { |
| s.removeBlock(head) |
| } |
| return true |
| } |
| |
| // Has reports whether x is an element of the set s. |
| func (s *Sparse) Has(x int) bool { |
| offset, i := offsetAndBitIndex(x) |
| if b := s.block(offset); b != nil { |
| return b.has(i) |
| } |
| return false |
| } |
| |
| // forEach applies function f to each element of the set s in order. |
| // |
| // f must not mutate s. Consequently, forEach is not safe to expose |
| // to clients. In any case, using "range s.AppendTo()" allows more |
| // natural control flow with continue/break/return. |
| // |
| func (s *Sparse) forEach(f func(int)) { |
| for b := s.start(); b != &s.root; b = b.next { |
| b.forEach(f) |
| } |
| } |
| |
| // Copy sets s to the value of x. |
| func (s *Sparse) Copy(x *Sparse) { |
| if s == x { |
| return |
| } |
| |
| xb := x.start() |
| sb := s.start() |
| for xb != &x.root { |
| if sb == &s.root { |
| sb = s.insertBlockBefore(sb) |
| } |
| sb.offset = xb.offset |
| sb.bits = xb.bits |
| xb = xb.next |
| sb = sb.next |
| } |
| s.discardTail(sb) |
| } |
| |
| // insertBlockBefore returns a new block, inserting it before next. |
| func (s *Sparse) insertBlockBefore(next *block) *block { |
| b := new(block) |
| b.next = next |
| b.prev = next.prev |
| b.prev.next = b |
| next.prev = b |
| return b |
| } |
| |
| // discardTail removes block b and all its successors from s. |
| func (s *Sparse) discardTail(b *block) { |
| if b != &s.root { |
| b.prev.next = &s.root |
| s.root.prev = b.prev |
| } |
| } |
| |
| // IntersectionWith sets s to the intersection s ∩ x. |
| func (s *Sparse) IntersectionWith(x *Sparse) { |
| if s == x { |
| return |
| } |
| |
| xb := x.start() |
| sb := s.start() |
| for xb != &x.root && sb != &s.root { |
| switch { |
| case xb.offset < sb.offset: |
| xb = xb.next |
| |
| case xb.offset > sb.offset: |
| sb = sb.next |
| s.removeBlock(sb.prev) |
| |
| default: |
| var sum word |
| for i := range sb.bits { |
| r := xb.bits[i] & sb.bits[i] |
| sb.bits[i] = r |
| sum |= r |
| } |
| if sum != 0 { |
| sb = sb.next |
| } else { |
| // sb will be overwritten or removed |
| } |
| |
| xb = xb.next |
| } |
| } |
| |
| s.discardTail(sb) |
| } |
| |
| // Intersection sets s to the intersection x ∩ y. |
| func (s *Sparse) Intersection(x, y *Sparse) { |
| switch { |
| case s == x: |
| s.IntersectionWith(y) |
| return |
| case s == y: |
| s.IntersectionWith(x) |
| return |
| case x == y: |
| s.Copy(x) |
| return |
| } |
| |
| xb := x.start() |
| yb := y.start() |
| sb := s.start() |
| for xb != &x.root && yb != &y.root { |
| switch { |
| case xb.offset < yb.offset: |
| xb = xb.next |
| continue |
| case xb.offset > yb.offset: |
| yb = yb.next |
| continue |
| } |
| |
| if sb == &s.root { |
| sb = s.insertBlockBefore(sb) |
| } |
| sb.offset = xb.offset |
| |
| var sum word |
| for i := range sb.bits { |
| r := xb.bits[i] & yb.bits[i] |
| sb.bits[i] = r |
| sum |= r |
| } |
| if sum != 0 { |
| sb = sb.next |
| } else { |
| // sb will be overwritten or removed |
| } |
| |
| xb = xb.next |
| yb = yb.next |
| } |
| |
| s.discardTail(sb) |
| } |
| |
| // Intersects reports whether s ∩ x ≠ ∅. |
| func (s *Sparse) Intersects(x *Sparse) bool { |
| sb := s.start() |
| xb := x.start() |
| for sb != &s.root && xb != &x.root { |
| switch { |
| case xb.offset < sb.offset: |
| xb = xb.next |
| case xb.offset > sb.offset: |
| sb = sb.next |
| default: |
| for i := range sb.bits { |
| if sb.bits[i]&xb.bits[i] != 0 { |
| return true |
| } |
| } |
| sb = sb.next |
| xb = xb.next |
| } |
| } |
| return false |
| } |
| |
| // UnionWith sets s to the union s ∪ x, and reports whether s grew. |
| func (s *Sparse) UnionWith(x *Sparse) bool { |
| if s == x { |
| return false |
| } |
| |
| var changed bool |
| xb := x.start() |
| sb := s.start() |
| for xb != &x.root { |
| if sb != &s.root && sb.offset == xb.offset { |
| for i := range xb.bits { |
| if sb.bits[i] != xb.bits[i] { |
| sb.bits[i] |= xb.bits[i] |
| changed = true |
| } |
| } |
| xb = xb.next |
| } else if sb == &s.root || sb.offset > xb.offset { |
| sb = s.insertBlockBefore(sb) |
| sb.offset = xb.offset |
| sb.bits = xb.bits |
| changed = true |
| |
| xb = xb.next |
| } |
| sb = sb.next |
| } |
| return changed |
| } |
| |
| // Union sets s to the union x ∪ y. |
| func (s *Sparse) Union(x, y *Sparse) { |
| switch { |
| case x == y: |
| s.Copy(x) |
| return |
| case s == x: |
| s.UnionWith(y) |
| return |
| case s == y: |
| s.UnionWith(x) |
| return |
| } |
| |
| xb := x.start() |
| yb := y.start() |
| sb := s.start() |
| for xb != &x.root || yb != &y.root { |
| if sb == &s.root { |
| sb = s.insertBlockBefore(sb) |
| } |
| switch { |
| case yb == &y.root || (xb != &x.root && xb.offset < yb.offset): |
| sb.offset = xb.offset |
| sb.bits = xb.bits |
| xb = xb.next |
| |
| case xb == &x.root || (yb != &y.root && yb.offset < xb.offset): |
| sb.offset = yb.offset |
| sb.bits = yb.bits |
| yb = yb.next |
| |
| default: |
| sb.offset = xb.offset |
| for i := range xb.bits { |
| sb.bits[i] = xb.bits[i] | yb.bits[i] |
| } |
| xb = xb.next |
| yb = yb.next |
| } |
| sb = sb.next |
| } |
| |
| s.discardTail(sb) |
| } |
| |
| // DifferenceWith sets s to the difference s ∖ x. |
| func (s *Sparse) DifferenceWith(x *Sparse) { |
| if s == x { |
| s.Clear() |
| return |
| } |
| |
| xb := x.start() |
| sb := s.start() |
| for xb != &x.root && sb != &s.root { |
| switch { |
| case xb.offset > sb.offset: |
| sb = sb.next |
| |
| case xb.offset < sb.offset: |
| xb = xb.next |
| |
| default: |
| var sum word |
| for i := range sb.bits { |
| r := sb.bits[i] & ^xb.bits[i] |
| sb.bits[i] = r |
| sum |= r |
| } |
| sb = sb.next |
| xb = xb.next |
| |
| if sum == 0 { |
| s.removeBlock(sb.prev) |
| } |
| } |
| } |
| } |
| |
| // Difference sets s to the difference x ∖ y. |
| func (s *Sparse) Difference(x, y *Sparse) { |
| switch { |
| case x == y: |
| s.Clear() |
| return |
| case s == x: |
| s.DifferenceWith(y) |
| return |
| case s == y: |
| var y2 Sparse |
| y2.Copy(y) |
| s.Difference(x, &y2) |
| return |
| } |
| |
| xb := x.start() |
| yb := y.start() |
| sb := s.start() |
| for xb != &x.root && yb != &y.root { |
| if xb.offset > yb.offset { |
| // y has block, x has none |
| yb = yb.next |
| continue |
| } |
| |
| if sb == &s.root { |
| sb = s.insertBlockBefore(sb) |
| } |
| sb.offset = xb.offset |
| |
| switch { |
| case xb.offset < yb.offset: |
| // x has block, y has none |
| sb.bits = xb.bits |
| |
| sb = sb.next |
| |
| default: |
| // x and y have corresponding blocks |
| var sum word |
| for i := range sb.bits { |
| r := xb.bits[i] & ^yb.bits[i] |
| sb.bits[i] = r |
| sum |= r |
| } |
| if sum != 0 { |
| sb = sb.next |
| } else { |
| // sb will be overwritten or removed |
| } |
| |
| yb = yb.next |
| } |
| xb = xb.next |
| } |
| |
| for xb != &x.root { |
| if sb == &s.root { |
| sb = s.insertBlockBefore(sb) |
| } |
| sb.offset = xb.offset |
| sb.bits = xb.bits |
| sb = sb.next |
| |
| xb = xb.next |
| } |
| |
| s.discardTail(sb) |
| } |
| |
| // SymmetricDifferenceWith sets s to the symmetric difference s ∆ x. |
| func (s *Sparse) SymmetricDifferenceWith(x *Sparse) { |
| if s == x { |
| s.Clear() |
| return |
| } |
| |
| sb := s.start() |
| xb := x.start() |
| for xb != &x.root && sb != &s.root { |
| switch { |
| case sb.offset < xb.offset: |
| sb = sb.next |
| case xb.offset < sb.offset: |
| nb := s.insertBlockBefore(sb) |
| nb.offset = xb.offset |
| nb.bits = xb.bits |
| xb = xb.next |
| default: |
| var sum word |
| for i := range sb.bits { |
| r := sb.bits[i] ^ xb.bits[i] |
| sb.bits[i] = r |
| sum |= r |
| } |
| sb = sb.next |
| xb = xb.next |
| if sum == 0 { |
| s.removeBlock(sb.prev) |
| } |
| } |
| } |
| |
| for xb != &x.root { // append the tail of x to s |
| sb = s.insertBlockBefore(sb) |
| sb.offset = xb.offset |
| sb.bits = xb.bits |
| sb = sb.next |
| xb = xb.next |
| } |
| } |
| |
| // SymmetricDifference sets s to the symmetric difference x ∆ y. |
| func (s *Sparse) SymmetricDifference(x, y *Sparse) { |
| switch { |
| case x == y: |
| s.Clear() |
| return |
| case s == x: |
| s.SymmetricDifferenceWith(y) |
| return |
| case s == y: |
| s.SymmetricDifferenceWith(x) |
| return |
| } |
| |
| sb := s.start() |
| xb := x.start() |
| yb := y.start() |
| for xb != &x.root && yb != &y.root { |
| if sb == &s.root { |
| sb = s.insertBlockBefore(sb) |
| } |
| switch { |
| case yb.offset < xb.offset: |
| sb.offset = yb.offset |
| sb.bits = yb.bits |
| sb = sb.next |
| yb = yb.next |
| case xb.offset < yb.offset: |
| sb.offset = xb.offset |
| sb.bits = xb.bits |
| sb = sb.next |
| xb = xb.next |
| default: |
| var sum word |
| for i := range sb.bits { |
| r := xb.bits[i] ^ yb.bits[i] |
| sb.bits[i] = r |
| sum |= r |
| } |
| if sum != 0 { |
| sb.offset = xb.offset |
| sb = sb.next |
| } |
| xb = xb.next |
| yb = yb.next |
| } |
| } |
| |
| for xb != &x.root { // append the tail of x to s |
| if sb == &s.root { |
| sb = s.insertBlockBefore(sb) |
| } |
| sb.offset = xb.offset |
| sb.bits = xb.bits |
| sb = sb.next |
| xb = xb.next |
| } |
| |
| for yb != &y.root { // append the tail of y to s |
| if sb == &s.root { |
| sb = s.insertBlockBefore(sb) |
| } |
| sb.offset = yb.offset |
| sb.bits = yb.bits |
| sb = sb.next |
| yb = yb.next |
| } |
| |
| s.discardTail(sb) |
| } |
| |
| // SubsetOf reports whether s ∖ x = ∅. |
| func (s *Sparse) SubsetOf(x *Sparse) bool { |
| if s == x { |
| return true |
| } |
| |
| sb := s.start() |
| xb := x.start() |
| for sb != &s.root { |
| switch { |
| case xb == &x.root || xb.offset > sb.offset: |
| return false |
| case xb.offset < sb.offset: |
| xb = xb.next |
| default: |
| for i := range sb.bits { |
| if sb.bits[i]&^xb.bits[i] != 0 { |
| return false |
| } |
| } |
| sb = sb.next |
| xb = xb.next |
| } |
| } |
| return true |
| } |
| |
| // Equals reports whether the sets s and t have the same elements. |
| func (s *Sparse) Equals(t *Sparse) bool { |
| if s == t { |
| return true |
| } |
| sb := s.start() |
| tb := t.start() |
| for { |
| switch { |
| case sb == &s.root && tb == &t.root: |
| return true |
| case sb == &s.root || tb == &t.root: |
| return false |
| case sb.offset != tb.offset: |
| return false |
| case sb.bits != tb.bits: |
| return false |
| } |
| |
| sb = sb.next |
| tb = tb.next |
| } |
| } |
| |
| // String returns a human-readable description of the set s. |
| func (s *Sparse) String() string { |
| var buf bytes.Buffer |
| buf.WriteByte('{') |
| s.forEach(func(x int) { |
| if buf.Len() > 1 { |
| buf.WriteByte(' ') |
| } |
| fmt.Fprintf(&buf, "%d", x) |
| }) |
| buf.WriteByte('}') |
| return buf.String() |
| } |
| |
| // BitString returns the set as a string of 1s and 0s denoting the sum |
| // of the i'th powers of 2, for each i in s. A radix point, always |
| // preceded by a digit, appears if the sum is non-integral. |
| // |
| // Examples: |
| // {}.BitString() = "0" |
| // {4,5}.BitString() = "110000" |
| // {-3}.BitString() = "0.001" |
| // {-3,0,4,5}.BitString() = "110001.001" |
| // |
| func (s *Sparse) BitString() string { |
| if s.IsEmpty() { |
| return "0" |
| } |
| |
| min, max := s.Min(), s.Max() |
| var nbytes int |
| if max > 0 { |
| nbytes = max |
| } |
| nbytes++ // zero bit |
| radix := nbytes |
| if min < 0 { |
| nbytes += len(".") - min |
| } |
| |
| b := make([]byte, nbytes) |
| for i := range b { |
| b[i] = '0' |
| } |
| if radix < nbytes { |
| b[radix] = '.' |
| } |
| s.forEach(func(x int) { |
| if x >= 0 { |
| x += len(".") |
| } |
| b[radix-x] = '1' |
| }) |
| return string(b) |
| } |
| |
| // GoString returns a string showing the internal representation of |
| // the set s. |
| // |
| func (s *Sparse) GoString() string { |
| var buf bytes.Buffer |
| for b := s.start(); b != &s.root; b = b.next { |
| fmt.Fprintf(&buf, "block %p {offset=%d next=%p prev=%p", |
| b, b.offset, b.next, b.prev) |
| for _, w := range b.bits { |
| fmt.Fprintf(&buf, " 0%016x", w) |
| } |
| fmt.Fprintf(&buf, "}\n") |
| } |
| return buf.String() |
| } |
| |
| // AppendTo returns the result of appending the elements of s to slice |
| // in order. |
| func (s *Sparse) AppendTo(slice []int) []int { |
| s.forEach(func(x int) { |
| slice = append(slice, x) |
| }) |
| return slice |
| } |
| |
| // -- Testing/debugging ------------------------------------------------ |
| |
| // check returns an error if the representation invariants of s are violated. |
| func (s *Sparse) check() error { |
| if !s.root.empty() { |
| return fmt.Errorf("non-empty root block") |
| } |
| if s.root.offset != 0 { |
| return fmt.Errorf("root block has non-zero offset %d", s.root.offset) |
| } |
| for b := s.start(); b != &s.root; b = b.next { |
| if b.offset%bitsPerBlock != 0 { |
| return fmt.Errorf("bad offset modulo: %d", b.offset) |
| } |
| if b.empty() { |
| return fmt.Errorf("empty block") |
| } |
| if b.prev.next != b { |
| return fmt.Errorf("bad prev.next link") |
| } |
| if b.next.prev != b { |
| return fmt.Errorf("bad next.prev link") |
| } |
| if b.prev != &s.root { |
| if b.offset <= b.prev.offset { |
| return fmt.Errorf("bad offset order: b.offset=%d, prev.offset=%d", |
| b.offset, b.prev.offset) |
| } |
| } |
| } |
| return nil |
| } |