Skip to content

Commit c77dfc3

Browse files
committed
Add PreviousClear and PreviousSet functions
These are analogous to NextClear and NextSet but scan backwards. The current implementations are naive.
1 parent 417751b commit c77dfc3

File tree

2 files changed

+94
-0
lines changed

2 files changed

+94
-0
lines changed

bitset.go

+40
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,46 @@ func (b *BitSet) NextClear(i uint) (uint, bool) {
586586
return 0, false
587587
}
588588

589+
// PreviousSet returns the previous set bit from the specified index,
590+
// including possibly the current index
591+
// along with an error code (true = valid, false = no bit found i.e. all bits are clear)
592+
func (b *BitSet) PreviousSet(i uint) (uint, bool) {
593+
x := int(i >> log2WordSize)
594+
if x >= len(b.set) {
595+
return 0, false
596+
}
597+
for {
598+
if b.Test(i) {
599+
return i, true
600+
}
601+
if i == 0 {
602+
break
603+
}
604+
i--
605+
}
606+
return 0, false
607+
}
608+
609+
// PreviousClear returns the previous clear bit from the specified index,
610+
// including possibly the current index
611+
// along with an error code (true = valid, false = no clear bit found i.e. all bits are set)
612+
func (b *BitSet) PreviousClear(i uint) (uint, bool) {
613+
x := int(i >> log2WordSize)
614+
if x >= len(b.set) {
615+
return 0, false
616+
}
617+
for {
618+
if !b.Test(i) {
619+
return i, true
620+
}
621+
if i == 0 {
622+
break
623+
}
624+
i--
625+
}
626+
return 0, false
627+
}
628+
589629
// ClearAll clears the entire BitSet.
590630
// It does not free the memory.
591631
func (b *BitSet) ClearAll() *BitSet {

bitset_test.go

+54
Original file line numberDiff line numberDiff line change
@@ -2087,3 +2087,57 @@ func TestWord(t *testing.T) {
20872087
})
20882088
}
20892089
}
2090+
2091+
func TestPreviousSet(t *testing.T) {
2092+
v := New(10)
2093+
v.Set(0)
2094+
v.Set(2)
2095+
v.Set(4)
2096+
for _, tt := range []struct {
2097+
index uint
2098+
want uint
2099+
wantFound bool
2100+
}{
2101+
{0, 0, true},
2102+
{1, 0, true},
2103+
{2, 2, true},
2104+
{3, 2, true},
2105+
{4, 4, true},
2106+
{5, 4, true},
2107+
{1024, 0, false},
2108+
} {
2109+
t.Run(fmt.Sprintf("@%d", tt.index), func(t *testing.T) {
2110+
got, found := v.PreviousSet(tt.index)
2111+
if got != tt.want || found != tt.wantFound {
2112+
t.Errorf("PreviousSet(%d) = %d, %v, want %d, %v", tt.index, got, found, tt.want, tt.wantFound)
2113+
}
2114+
})
2115+
}
2116+
}
2117+
2118+
func TestPreviousClear(t *testing.T) {
2119+
v := New(10)
2120+
v.Set(0)
2121+
v.Set(2)
2122+
v.Set(4)
2123+
for _, tt := range []struct {
2124+
index uint
2125+
want uint
2126+
wantFound bool
2127+
}{
2128+
{0, 0, false},
2129+
{1, 1, true},
2130+
{2, 1, true},
2131+
{3, 3, true},
2132+
{4, 3, true},
2133+
{5, 5, true},
2134+
{1024, 0, false},
2135+
} {
2136+
t.Run(fmt.Sprintf("@%d", tt.index), func(t *testing.T) {
2137+
got, found := v.PreviousClear(tt.index)
2138+
if got != tt.want || found != tt.wantFound {
2139+
t.Errorf("PreviousClear(%d) = %d, %v, want %d, %v", tt.index, got, found, tt.want, tt.wantFound)
2140+
}
2141+
})
2142+
}
2143+
}

0 commit comments

Comments
 (0)