mirror of https://github.com/hashicorp/terraform
Use iterators for graph vertices (#36558)
* Use iterators for graph vertices * use func filter * use type param instead of function filter One type parameter seem to be enough instead of 2pull/37200/head
parent
eaf3061789
commit
2a79f5fa53
@ -0,0 +1,74 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package dag
|
||||
|
||||
import (
|
||||
"iter"
|
||||
"slices"
|
||||
)
|
||||
|
||||
type VertexSeq[T Vertex] iter.Seq[T]
|
||||
|
||||
func (seq VertexSeq[T]) Collect() []T {
|
||||
return slices.Collect(iter.Seq[T](seq))
|
||||
}
|
||||
|
||||
func (seq VertexSeq[T]) AsGeneric() VertexSeq[Vertex] {
|
||||
return func(yield func(Vertex) bool) {
|
||||
for v := range seq {
|
||||
if !yield(v) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Vertices returns an iterator over all the vertices in the graph.
|
||||
func (g *Graph) VerticesSeq() VertexSeq[Vertex] {
|
||||
return func(yield func(v Vertex) bool) {
|
||||
for _, v := range g.vertices {
|
||||
v, ok := v.(Vertex)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if !yield(v) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SelectSeq filters a sequence to include only elements that can be type-asserted to type U.
|
||||
// It returns a new sequence containing only the matching elements.
|
||||
// The yield function can return false to stop iteration early.
|
||||
func SelectSeq[U Vertex](seq VertexSeq[Vertex]) VertexSeq[U] {
|
||||
return func(yield func(U) bool) {
|
||||
for v := range seq {
|
||||
// if the item is not of the type we're looking for, skip it
|
||||
u, ok := any(v).(U)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if !yield(u) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ExcludeSeq filters a sequence to exclude elements that can be type-asserted to type U.
|
||||
// It returns a new sequence containing only the non-matching elements.
|
||||
// The yield function can return false to stop iteration early.
|
||||
func ExcludeSeq[U Vertex](seq VertexSeq[Vertex]) VertexSeq[Vertex] {
|
||||
return func(yield func(Vertex) bool) {
|
||||
for v := range seq {
|
||||
if _, ok := any(v).(U); ok {
|
||||
continue
|
||||
}
|
||||
if !yield(v) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package dag
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Mock implementation of SeqVertex for testing
|
||||
type MockVertex struct {
|
||||
id int
|
||||
}
|
||||
|
||||
func (v MockVertex) ZeroValue() any {
|
||||
return MockVertex{}
|
||||
}
|
||||
|
||||
type MockVertex2 struct {
|
||||
id int
|
||||
}
|
||||
|
||||
func TestSelectSeq(t *testing.T) {
|
||||
v1 := MockVertex{id: 1}
|
||||
v11 := MockVertex{id: 11}
|
||||
v2 := MockVertex2{id: 2}
|
||||
vertices := Set{v1: v1, v11: v11, v2: v2}
|
||||
|
||||
graph := &Graph{vertices: vertices}
|
||||
seq := SelectSeq[MockVertex](graph.VerticesSeq())
|
||||
t.Run("Select objects of given type", func(t *testing.T) {
|
||||
count := len(seq.Collect())
|
||||
if count != 2 {
|
||||
t.Errorf("Expected 2, got %d", count)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Returns empty when looking for incompatible types", func(t *testing.T) {
|
||||
seq := SelectSeq[MockVertex2](seq.AsGeneric())
|
||||
count := len(seq.Collect())
|
||||
if count != 0 {
|
||||
t.Errorf("Expected empty, got %d", count)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Select objects of given interface", func(t *testing.T) {
|
||||
seq := SelectSeq[interface{ ZeroValue() any }](graph.VerticesSeq())
|
||||
count := len(seq.Collect())
|
||||
if count != 2 {
|
||||
t.Errorf("Expected 1, got %d", count)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestExcludeSeq(t *testing.T) {
|
||||
v1 := MockVertex{id: 1}
|
||||
v11 := MockVertex{id: 11}
|
||||
v2 := MockVertex2{id: 2}
|
||||
vertices := Set{v1: v1, v11: v11, v2: v2}
|
||||
|
||||
graph := &Graph{vertices: vertices}
|
||||
seq := ExcludeSeq[MockVertex](graph.VerticesSeq())
|
||||
t.Run("Exclude objects of given type", func(t *testing.T) {
|
||||
count := len(seq.Collect())
|
||||
if count != 1 {
|
||||
t.Errorf("Expected 1, got %d", count)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Returns empty when looking for incompatible types", func(t *testing.T) {
|
||||
seq := ExcludeSeq[MockVertex2](seq)
|
||||
count := len(seq.Collect())
|
||||
if count != 0 {
|
||||
t.Errorf("Expected empty, got %d", count)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Exclude objects of given interface", func(t *testing.T) {
|
||||
seq := ExcludeSeq[interface{ ZeroValue() any }](graph.VerticesSeq())
|
||||
count := len(seq.Collect())
|
||||
if count != 1 {
|
||||
t.Errorf("Expected 1, got %d", count)
|
||||
}
|
||||
})
|
||||
}
|
||||
Loading…
Reference in new issue