1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
|
package main
// A Backlog represents a queue of file paths that may be received while we're
// still running a command. There are a couple of different policies for how to
// handle this. If there are no {} (substitution sequences) in the command, then
// we only need to preserve one of the paths. If there is a {}, then we need to
// preserve each unique path in the backlog.
type Backlog interface {
// Add a path to the backlog.
Add(path string)
// Show what path should be processed next.
Next() string
// Remove the next path from the backlog and return whether
// the backlog is now empty.
RemoveOne() (empty bool)
}
// A UnifiedBacklog only remembers one backlog item at a time.
type UnifiedBacklog struct {
s string
empty bool
}
func NewUnifiedBacklog() *UnifiedBacklog {
return &UnifiedBacklog{empty: true}
}
// Add adds path to b if there is not a path there currently.
// Otherwise it discards it.
func (b *UnifiedBacklog) Add(path string) {
if b.empty {
b.s = path
b.empty = false
}
}
// Next returns the path in b.
func (b *UnifiedBacklog) Next() string {
if b.empty {
panic("Next() called on empty backlog")
}
return b.s
}
// RemoveOne removes the path in b.
func (b *UnifiedBacklog) RemoveOne() bool {
if b.empty {
panic("RemoveOne() called on empty backlog")
}
b.empty = true
b.s = ""
return true
}
// A UniqueFilesBacklog keeps a set of the paths it has received.
type UniqueFilesBacklog struct {
empty bool
next string
rest map[string]struct{}
}
func NewUniqueFilesBacklog() *UniqueFilesBacklog {
return &UniqueFilesBacklog{
empty: true,
next: "",
rest: make(map[string]struct{}),
}
}
// Add adds path to the set of files in b.
func (b *UniqueFilesBacklog) Add(path string) {
defer func() { b.empty = false }()
if b.empty {
b.next = path
return
}
if path == b.next {
return
}
b.rest[path] = struct{}{}
}
// Next returns one of the paths in b.
func (b *UniqueFilesBacklog) Next() string {
if b.empty {
panic("Next() called on empty backlog")
}
return b.next
}
// RemoveOne removes one of the paths from b (the same path that was returned by
// a preceding call to Next).
func (b *UniqueFilesBacklog) RemoveOne() bool {
if b.empty {
panic("RemoveOne() called on empty backlog")
}
if len(b.rest) == 0 {
b.next = ""
b.empty = true
return true
}
for next := range b.rest {
b.next = next
break
}
delete(b.rest, b.next)
return false
}
|