diff options
| author | 2026-03-06 10:59:53 +0800 | |
|---|---|---|
| committer | 2026-03-06 10:59:53 +0800 | |
| commit | 95f8f3d45fe077042df4fd4afa73d4e419bc9974 (patch) | |
| tree | 1e650b788eb4fbe5fc61ad0df700de58ebba40c5 /reachability/walk_seq.go | |
| parent | format/commitgraph: Split layer files (diff) | |
| signature | No signature | |
reachability: Split walk files
Diffstat (limited to 'reachability/walk_seq.go')
| -rw-r--r-- | reachability/walk_seq.go | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/reachability/walk_seq.go b/reachability/walk_seq.go new file mode 100644 index 00000000..ad3415d1 --- /dev/null +++ b/reachability/walk_seq.go @@ -0,0 +1,69 @@ +package reachability + +import ( + "errors" + "iter" + + "codeberg.org/lindenii/furgit/objectid" +) + +// Seq returns the traversal sequence. It is single-use. +func (walk *Walk) Seq() iter.Seq[objectid.ObjectID] { + if walk.seqUsed { + return func(yield func(objectid.ObjectID) bool) { + _ = yield + + if walk.err == nil { + walk.err = errors.New("reachability: walk sequence already consumed") + } + } + } + + walk.seqUsed = true + + return func(yield func(objectid.ObjectID) bool) { + if walk.err != nil { + return + } + + stack := walk.initialStack() + + var err error + + visited := make(map[objectid.ObjectID]struct{}, len(stack)) + for len(stack) > 0 { + item := stack[len(stack)-1] + stack = stack[:len(stack)-1] + + if containsOID(walk.haves, item.id) { + continue + } + + if _, ok := visited[item.id]; ok { + continue + } + + visited[item.id] = struct{}{} + + var next []walkItem + + next, err = walk.expand(item) + if err != nil { + walk.err = err + + return + } + + if !yield(item.id) { + return + } + + stack = append(stack, next...) + } + } +} + +// Err returns the terminal error, if any, once Seq has been consumed. +func (walk *Walk) Err() error { + return walk.err +} |
