github.com/anchore/syft@v1.38.2/syft/file/coordinate_set.go (about)

     1  package file
     2  
     3  import (
     4  	"sort"
     5  
     6  	"github.com/gohugoio/hashstructure"
     7  	"github.com/scylladb/go-set/strset"
     8  )
     9  
    10  // CoordinateSet provides a unique collection of Coordinates with set operations.
    11  type CoordinateSet struct {
    12  	set map[Coordinates]struct{}
    13  }
    14  
    15  func NewCoordinateSet(coordinates ...Coordinates) (s CoordinateSet) {
    16  	for _, l := range coordinates {
    17  		s.Add(l)
    18  	}
    19  
    20  	return s
    21  }
    22  
    23  func (s *CoordinateSet) Add(coordinates ...Coordinates) {
    24  	if s.set == nil {
    25  		s.set = make(map[Coordinates]struct{})
    26  	}
    27  	for _, l := range coordinates {
    28  		s.set[l] = struct{}{}
    29  	}
    30  }
    31  
    32  func (s CoordinateSet) Remove(coordinates ...Coordinates) {
    33  	if s.set == nil {
    34  		return
    35  	}
    36  	for _, l := range coordinates {
    37  		delete(s.set, l)
    38  	}
    39  }
    40  
    41  func (s CoordinateSet) Contains(l Coordinates) bool {
    42  	if s.set == nil {
    43  		return false
    44  	}
    45  	_, ok := s.set[l]
    46  	return ok
    47  }
    48  
    49  func (s CoordinateSet) Paths() []string {
    50  	if s.set == nil {
    51  		return nil
    52  	}
    53  
    54  	paths := strset.New()
    55  	for _, c := range s.ToSlice() {
    56  		paths.Add(c.RealPath)
    57  	}
    58  	pathSlice := paths.List()
    59  	sort.Strings(pathSlice)
    60  	return pathSlice
    61  }
    62  
    63  func (s CoordinateSet) ToSlice(sorters ...func(a, b Coordinates) int) []Coordinates {
    64  	coordinates := s.ToUnorderedSlice()
    65  
    66  	var sorted bool
    67  	for _, sorter := range sorters {
    68  		if sorter == nil {
    69  			continue
    70  		}
    71  		sort.Slice(coordinates, func(i, j int) bool {
    72  			return sorter(coordinates[i], coordinates[j]) < 0
    73  		})
    74  		sorted = true
    75  		break
    76  	}
    77  
    78  	if !sorted {
    79  		sort.SliceStable(coordinates, func(i, j int) bool {
    80  			if coordinates[i].FileSystemID == coordinates[j].FileSystemID {
    81  				return coordinates[i].RealPath < coordinates[j].RealPath
    82  			}
    83  			return coordinates[i].FileSystemID < coordinates[j].FileSystemID
    84  		})
    85  	}
    86  
    87  	return coordinates
    88  }
    89  
    90  func (s CoordinateSet) ToUnorderedSlice() []Coordinates {
    91  	if s.set == nil {
    92  		return nil
    93  	}
    94  	coordinates := make([]Coordinates, len(s.set))
    95  	idx := 0
    96  	for v := range s.set {
    97  		coordinates[idx] = v
    98  		idx++
    99  	}
   100  	return coordinates
   101  }
   102  
   103  func (s CoordinateSet) Hash() (uint64, error) {
   104  	return hashstructure.Hash(s.ToSlice(), &hashstructure.HashOptions{
   105  		ZeroNil:      true,
   106  		SlicesAsSets: true,
   107  	})
   108  }