diff --git a/src/restic/pack/blob_set.go b/src/restic/pack/blob_set.go new file mode 100644 index 000000000..686ea9315 --- /dev/null +++ b/src/restic/pack/blob_set.go @@ -0,0 +1,109 @@ +package pack + +import "sort" + +// BlobSet is a set of blobs. +type BlobSet map[Handle]struct{} + +// NewBlobSet returns a new BlobSet, populated with ids. +func NewBlobSet(handles ...Handle) BlobSet { + m := make(BlobSet) + for _, h := range handles { + m[h] = struct{}{} + } + + return m +} + +// Has returns true iff id is contained in the set. +func (s BlobSet) Has(h Handle) bool { + _, ok := s[h] + return ok +} + +// Insert adds id to the set. +func (s BlobSet) Insert(h Handle) { + s[h] = struct{}{} +} + +// Delete removes id from the set. +func (s BlobSet) Delete(h Handle) { + delete(s, h) +} + +// Equals returns true iff s equals other. +func (s BlobSet) Equals(other BlobSet) bool { + if len(s) != len(other) { + return false + } + + for h := range s { + if _, ok := other[h]; !ok { + return false + } + } + + return true +} + +// Merge adds the blobs in other to the current set. +func (s BlobSet) Merge(other BlobSet) { + for h := range other { + s.Insert(h) + } +} + +// Intersect returns a new set containing the handles that are present in both sets. +func (s BlobSet) Intersect(other BlobSet) (result BlobSet) { + result = NewBlobSet() + + set1 := s + set2 := other + + // iterate over the smaller set + if len(set2) < len(set1) { + set1, set2 = set2, set1 + } + + for h := range set1 { + if set2.Has(h) { + result.Insert(h) + } + } + + return result +} + +// Sub returns a new set containing all handles that are present in s but not in +// other. +func (s BlobSet) Sub(other BlobSet) (result BlobSet) { + result = NewBlobSet() + for h := range s { + if !other.Has(h) { + result.Insert(h) + } + } + + return result +} + +// List returns a slice of all Handles in the set. +func (s BlobSet) List() Handles { + list := make(Handles, 0, len(s)) + for h := range s { + list = append(list, h) + } + + sort.Sort(list) + + return list +} + +func (s BlobSet) String() string { + str := s.List().String() + if len(str) < 2 { + return "{}" + } + + return "{" + str[1:len(str)-1] + "}" +} diff --git a/src/restic/pack/handle.go b/src/restic/pack/handle.go new file mode 100644 index 000000000..b47aa1293 --- /dev/null +++ b/src/restic/pack/handle.go @@ -0,0 +1,59 @@ +package pack + +import ( + "fmt" + "restic/backend" +) + +// Handle identifies a blob of a given type. +type Handle struct { + ID backend.ID + Type BlobType +} + +func (h Handle) String() string { + name := h.ID.String() + if len(name) > 10 { + name = name[:10] + } + return fmt.Sprintf("<%s/%s>", h.Type, name) +} + +// Handles is an ordered list of Handles that implements sort.Interface. +type Handles []Handle + +func (h Handles) Len() int { + return len(h) +} + +func (h Handles) Less(i, j int) bool { + if h[i].Type != h[j].Type { + return h[i].Type < h[j].Type + } + + for k, b := range h[i].ID { + if b == h[j].ID[k] { + continue + } + + if b < h[j].ID[k] { + return true + } + + return false + } + + return false +} + +func (h Handles) Swap(i, j int) { + h[i], h[j] = h[j], h[i] +} + +func (h Handles) String() string { + elements := make([]string, 0, len(h)) + for _, e := range h { + elements = append(elements, e.String()) + } + return fmt.Sprintf("%v", elements) +}