Skip to content
This repository was archived by the owner on Sep 30, 2024. It is now read-only.

Commit e9108b3

Browse files
chore: Add collection type - OrderedSet (#63469)
It is missing from the stdlib and the orderedmap library we're using.
1 parent ec90be4 commit e9108b3

File tree

3 files changed

+77
-0
lines changed

3 files changed

+77
-0
lines changed

internal/collections/BUILD.bazel

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
44
go_library(
55
name = "collections",
66
srcs = [
7+
"ordered_set.go",
78
"set.go",
89
"slice_utils.go",
910
],
1011
importpath = "github.com/sourcegraph/sourcegraph/internal/collections",
1112
visibility = ["//:__subpackages__"],
1213
deps = [
1314
"//lib/errors",
15+
"@com_github_wk8_go_ordered_map_v2//:go-ordered-map",
1416
"@org_golang_x_exp//constraints",
1517
"@org_golang_x_exp//maps",
1618
],
@@ -20,6 +22,7 @@ go_test(
2022
name = "collections_test",
2123
timeout = "short",
2224
srcs = [
25+
"ordered_set_test.go",
2326
"set_test.go",
2427
"slice_utils_test.go",
2528
],

internal/collections/ordered_set.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package collections
2+
3+
import orderedmap "github.com/wk8/go-ordered-map/v2"
4+
5+
// OrderedSet keeps track of values in insertion order.
6+
type OrderedSet[T comparable] orderedmap.OrderedMap[T, struct{}]
7+
8+
// NewOrderedSet creates a OrderedSet[T] with the given values.
9+
// T must be a comparable type (implementing sort.Interface or == operator).
10+
func NewOrderedSet[T comparable](values ...T) *OrderedSet[T] {
11+
s := OrderedSet[T](*orderedmap.New[T, struct{}]())
12+
s.Add(values...)
13+
return &s
14+
}
15+
16+
func (s *OrderedSet[T]) impl() *orderedmap.OrderedMap[T, struct{}] {
17+
return (*orderedmap.OrderedMap[T, struct{}])(s)
18+
}
19+
20+
func (s *OrderedSet[T]) Add(values ...T) {
21+
for _, v := range values {
22+
s.impl().Set(v, struct{}{})
23+
}
24+
}
25+
26+
func (s *OrderedSet[T]) Remove(values ...T) {
27+
for _, v := range values {
28+
s.impl().Delete(v)
29+
}
30+
}
31+
32+
func (s *OrderedSet[T]) Has(value T) bool {
33+
_, found := s.impl().Get(value)
34+
return found
35+
}
36+
37+
// Values returns a slice with all the values in the set.
38+
// The values are returned in insertion order.
39+
func (s *OrderedSet[T]) Values() []T {
40+
out := make([]T, 0, s.impl().Len())
41+
for x := s.impl().Oldest(); x != nil; x = x.Next() {
42+
out = append(out, x.Key)
43+
}
44+
return out
45+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package collections
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
"pgregory.net/rapid"
8+
)
9+
10+
func TestOrderedSet(t *testing.T) {
11+
rapid.Check(t, func(t *rapid.T) {
12+
data := rapid.SliceOfN(rapid.IntRange(-3, 6), 0, 10).Draw(t, "data")
13+
set := NewSet(data...)
14+
uniquedData := set.Values()
15+
ordset := NewOrderedSet(uniquedData...)
16+
require.Equal(t, uniquedData, ordset.Values())
17+
18+
otherData := rapid.SliceOfN(rapid.IntRange(-5, 5), 10, 10).Draw(t, "data")
19+
for _, x := range otherData {
20+
require.Equal(t, set.Has(x), ordset.Has(x))
21+
}
22+
23+
for _, x := range uniquedData {
24+
require.True(t, ordset.Has(x))
25+
ordset.Remove(x)
26+
require.False(t, ordset.Has(x))
27+
}
28+
})
29+
}

0 commit comments

Comments
 (0)