Skip to content

Commit d995866

Browse files
committed
heaputil: add package with helper functions for working with heaps
This patch adds a new `heaputil` containing helper functions for working with heaps. As of now, it only contains a single `Valid` function which returns whether a heap is a valid heap based on the min-heap invariant defined by `heap.Interface`. The reasoning for creating a new package instead of reusing the existing `heap` package is that that package is intended to be a type-safe copy of the standard library package with the same name. Release note: None
1 parent 2efdf20 commit d995866

File tree

4 files changed

+118
-0
lines changed

4 files changed

+118
-0
lines changed

pkg/BUILD.bazel

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,7 @@ ALL_TESTS = [
727727
"//pkg/util/cloudinfo:cloudinfo_test",
728728
"//pkg/util/collatedstring:collatedstring_test",
729729
"//pkg/util/container/heap:heap_test",
730+
"//pkg/util/container/heaputil:heaputil_test",
730731
"//pkg/util/container/list:list_test",
731732
"//pkg/util/container/ring:ring_test",
732733
"//pkg/util/ctxgroup:ctxgroup_test",
@@ -2570,6 +2571,8 @@ GO_TARGETS = [
25702571
"//pkg/util/collatedstring:collatedstring_test",
25712572
"//pkg/util/container/heap:heap",
25722573
"//pkg/util/container/heap:heap_test",
2574+
"//pkg/util/container/heaputil:heaputil",
2575+
"//pkg/util/container/heaputil:heaputil_test",
25732576
"//pkg/util/container/list:list",
25742577
"//pkg/util/container/list:list_test",
25752578
"//pkg/util/container/ring:ring",
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
2+
3+
go_library(
4+
name = "heaputil",
5+
srcs = ["heaputil.go"],
6+
importpath = "github.com/cockroachdb/cockroach/pkg/util/container/heaputil",
7+
visibility = ["//visibility:public"],
8+
deps = ["//pkg/util/container/heap"],
9+
)
10+
11+
go_test(
12+
name = "heaputil_test",
13+
srcs = ["heaputil_test.go"],
14+
deps = [
15+
":heaputil",
16+
"//pkg/util/container/heap",
17+
"@com_github_stretchr_testify//require",
18+
],
19+
)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2025 The Cockroach Authors.
2+
//
3+
// Use of this software is governed by the CockroachDB Software License
4+
// included in the /LICENSE file.
5+
6+
// Package heaputil provides helper functions for working with heaps.
7+
package heaputil
8+
9+
import "github.com/cockroachdb/cockroach/pkg/util/container/heap"
10+
11+
// Valid returns whether a heap is a valid heap based on the min-heap
12+
// invariant defined by heap.Interface.
13+
func Valid[T any](h heap.Interface[T]) bool {
14+
n := h.Len()
15+
for i := 0; i < n; i++ {
16+
left, right := 2*i+1, 2*i+2
17+
if left < n && h.Less(left, i) {
18+
return false
19+
}
20+
if right < n && h.Less(right, i) {
21+
return false
22+
}
23+
}
24+
return true
25+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright 2025 The Cockroach Authors.
2+
//
3+
// Use of this software is governed by the CockroachDB Software License
4+
// included in the /LICENSE file.
5+
6+
package heaputil_test
7+
8+
import (
9+
"testing"
10+
11+
"github.com/cockroachdb/cockroach/pkg/util/container/heap"
12+
"github.com/cockroachdb/cockroach/pkg/util/container/heaputil"
13+
"github.com/stretchr/testify/require"
14+
)
15+
16+
func TestValid(t *testing.T) {
17+
for name, tc := range map[string]struct {
18+
h intHeap
19+
valid bool
20+
}{
21+
"nil heap": {
22+
h: nil,
23+
valid: true,
24+
},
25+
"empty heap": {
26+
h: []int{},
27+
valid: true,
28+
},
29+
"sorted heap": {
30+
h: []int{1, 2, 3, 4, 5, 6},
31+
valid: true,
32+
},
33+
"valid heap": {
34+
h: []int{2, 4, 6, 5, 9, 7},
35+
valid: true,
36+
},
37+
"invalid heap due to left child": {
38+
h: []int{5, 1, 7},
39+
valid: false,
40+
},
41+
"invalid heap due to right child": {
42+
h: []int{4, 6, 1},
43+
valid: false,
44+
},
45+
} {
46+
t.Run(name, func(t *testing.T) {
47+
actual := heaputil.Valid(&tc.h)
48+
require.Equal(t, tc.valid, actual)
49+
})
50+
}
51+
}
52+
53+
type intHeap []int
54+
55+
var _ heap.Interface[int] = (*intHeap)(nil)
56+
57+
func (h intHeap) Len() int { return len(h) }
58+
func (h intHeap) Less(i, j int) bool { return h[i] < h[j] }
59+
func (h intHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
60+
61+
func (h *intHeap) Push(x int) {
62+
*h = append(*h, x)
63+
}
64+
65+
func (h *intHeap) Pop() int {
66+
old := *h
67+
n := len(old)
68+
x := old[n-1]
69+
*h = old[:n-1]
70+
return x
71+
}

0 commit comments

Comments
 (0)