| // Copyright 2013 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 bitvec | |
| import ( | |
| "math/bits" | |
| "cmd/compile/internal/base" | |
| ) | |
| const ( | |
| wordBits = 32 | |
| wordMask = wordBits - 1 | |
| wordShift = 5 | |
| ) | |
| // A BitVec is a bit vector. | |
| type BitVec struct { | |
| N int32 // number of bits in vector | |
| B []uint32 // words holding bits | |
| } | |
| func New(n int32) BitVec { | |
| nword := (n + wordBits - 1) / wordBits | |
| return BitVec{n, make([]uint32, nword)} | |
| } | |
| type Bulk struct { | |
| words []uint32 | |
| nbit int32 | |
| nword int32 | |
| } | |
| func NewBulk(nbit int32, count int32) Bulk { | |
| nword := (nbit + wordBits - 1) / wordBits | |
| size := int64(nword) * int64(count) | |
| if int64(int32(size*4)) != size*4 { | |
| base.Fatalf("NewBulk too big: nbit=%d count=%d nword=%d size=%d", nbit, count, nword, size) | |
| } | |
| return Bulk{ | |
| words: make([]uint32, size), | |
| nbit: nbit, | |
| nword: nword, | |
| } | |
| } | |
| func (b *Bulk) Next() BitVec { | |
| out := BitVec{b.nbit, b.words[:b.nword]} | |
| b.words = b.words[b.nword:] | |
| return out | |
| } | |
| func (bv1 BitVec) Eq(bv2 BitVec) bool { | |
| if bv1.N != bv2.N { | |
| base.Fatalf("bvequal: lengths %d and %d are not equal", bv1.N, bv2.N) | |
| } | |
| for i, x := range bv1.B { | |
| if x != bv2.B[i] { | |
| return false | |
| } | |
| } | |
| return true | |
| } | |
| func (dst BitVec) Copy(src BitVec) { | |
| copy(dst.B, src.B) | |
| } | |
| func (bv BitVec) Get(i int32) bool { | |
| if i < 0 || i >= bv.N { | |
| base.Fatalf("bvget: index %d is out of bounds with length %d\n", i, bv.N) | |
| } | |
| mask := uint32(1 << uint(i%wordBits)) | |
| return bv.B[i>>wordShift]&mask != 0 | |
| } | |
| func (bv BitVec) Set(i int32) { | |
| if i < 0 || i >= bv.N { | |
| base.Fatalf("bvset: index %d is out of bounds with length %d\n", i, bv.N) | |
| } | |
| mask := uint32(1 << uint(i%wordBits)) | |
| bv.B[i/wordBits] |= mask | |
| } | |
| func (bv BitVec) Unset(i int32) { | |
| if i < 0 || i >= bv.N { | |
| base.Fatalf("bvunset: index %d is out of bounds with length %d\n", i, bv.N) | |
| } | |
| mask := uint32(1 << uint(i%wordBits)) | |
| bv.B[i/wordBits] &^= mask | |
| } | |
| // bvnext returns the smallest index >= i for which bvget(bv, i) == 1. | |
| // If there is no such index, bvnext returns -1. | |
| func (bv BitVec) Next(i int32) int32 { | |
| if i >= bv.N { | |
| return -1 | |
| } | |
| // Jump i ahead to next word with bits. | |
| if bv.B[i>>wordShift]>>uint(i&wordMask) == 0 { | |
| i &^= wordMask | |
| i += wordBits | |
| for i < bv.N && bv.B[i>>wordShift] == 0 { | |
| i += wordBits | |
| } | |
| } | |
| if i >= bv.N { | |
| return -1 | |
| } | |
| // Find 1 bit. | |
| w := bv.B[i>>wordShift] >> uint(i&wordMask) | |
| i += int32(bits.TrailingZeros32(w)) | |
| return i | |
| } | |
| func (bv BitVec) IsEmpty() bool { | |
| for _, x := range bv.B { | |
| if x != 0 { | |
| return false | |
| } | |
| } | |
| return true | |
| } | |
| func (bv BitVec) Not() { | |
| for i, x := range bv.B { | |
| bv.B[i] = ^x | |
| } | |
| } | |
| // union | |
| func (dst BitVec) Or(src1, src2 BitVec) { | |
| if len(src1.B) == 0 { | |
| return | |
| } | |
| _, _ = dst.B[len(src1.B)-1], src2.B[len(src1.B)-1] // hoist bounds checks out of the loop | |
| for i, x := range src1.B { | |
| dst.B[i] = x | src2.B[i] | |
| } | |
| } | |
| // intersection | |
| func (dst BitVec) And(src1, src2 BitVec) { | |
| if len(src1.B) == 0 { | |
| return | |
| } | |
| _, _ = dst.B[len(src1.B)-1], src2.B[len(src1.B)-1] // hoist bounds checks out of the loop | |
| for i, x := range src1.B { | |
| dst.B[i] = x & src2.B[i] | |
| } | |
| } | |
| // difference | |
| func (dst BitVec) AndNot(src1, src2 BitVec) { | |
| if len(src1.B) == 0 { | |
| return | |
| } | |
| _, _ = dst.B[len(src1.B)-1], src2.B[len(src1.B)-1] // hoist bounds checks out of the loop | |
| for i, x := range src1.B { | |
| dst.B[i] = x &^ src2.B[i] | |
| } | |
| } | |
| func (bv BitVec) String() string { | |
| s := make([]byte, 2+bv.N) | |
| copy(s, "#*") | |
| for i := int32(0); i < bv.N; i++ { | |
| ch := byte('0') | |
| if bv.Get(i) { | |
| ch = '1' | |
| } | |
| s[2+i] = ch | |
| } | |
| return string(s) | |
| } | |
| func (bv BitVec) Clear() { | |
| for i := range bv.B { | |
| bv.B[i] = 0 | |
| } | |
| } |