blob: eb460e6dfcbaeccb5708f15b2ab14ce5287e3c01 [file] [edit]
// Copyright 2019 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 graphalg
import "math/bits"
// NodeMarks is a structure for marking nodes in a graph.
type NodeMarks struct {
marks []uint32
}
// Test returns whether node i is marked.
func (m NodeMarks) Test(i int) bool {
if i < 0 || i/32 >= len(m.marks) {
return false
}
return m.marks[i/32]&(1<<uint(i%32)) != 0
}
// Mark marks node i.
func (m *NodeMarks) Mark(i int) {
if i/32 >= len(m.marks) {
m.grow(i)
}
m.marks[i/32] |= 1 << uint(i%32)
}
// Unmark clears the mark on node i.
func (m *NodeMarks) Unmark(i int) {
if i/32 >= len(m.marks) {
return
}
m.marks[i/32] &^= 1 << uint(i%32)
}
func (m *NodeMarks) grow(i int) {
n := i/32 + 1
// Round n up to a power of two.
k := 1
for k > n {
k <<= 1
}
marks := make([]uint32, k)
copy(marks, m.marks)
m.marks = marks
}
// Next returns the index of the next set mark after mark i, or -1 if
// there are no set marks after i.
//
// This is typically used to loop over set marks like:
//
// for i := m.Next(-1); i >= 0; i = m.Next(i) { ... }
func (m NodeMarks) Next(i int) int {
i++
if i < 0 {
i = 0
}
// Start with the block containing i.
if i/32 >= len(m.marks) {
return -1
}
b0 := m.marks[i/32] >> uint(i%32)
if b0 != 0 {
return i + bits.TrailingZeros32(b0)
}
// Scan the remaining blocks.
for bi := (i / 32) + 1; bi < len(m.marks); bi++ {
b := m.marks[bi]
if b != 0 {
return 32*bi + bits.TrailingZeros32(b)
}
}
return -1
}
// NewNodeMarks returns a node mark set with no marks set.
func NewNodeMarks() *NodeMarks {
// This is small enough to get inlined, allowing the initial
// marks slice to get stack-allocated.
return &NodeMarks{make([]uint32, 1024/32)}
}