1package dependency
2
3import (
4	"strings"
5	"sync"
6)
7
8// Set is a dependency-specific set implementation. Relative ordering is
9// preserved.
10type Set struct {
11	once sync.Once
12	sync.RWMutex
13	list []string
14	set  map[string]Dependency
15}
16
17// Add adds a new element to the set if it does not already exist.
18func (s *Set) Add(d Dependency) bool {
19	s.init()
20	s.Lock()
21	defer s.Unlock()
22	if _, ok := s.set[d.String()]; !ok {
23		s.list = append(s.list, d.String())
24		s.set[d.String()] = d
25		return true
26	}
27	return false
28}
29
30// Get retrieves a single element from the set by name.
31func (s *Set) Get(v string) Dependency {
32	s.RLock()
33	defer s.RUnlock()
34	return s.set[v]
35}
36
37// List returns the insertion-ordered list of dependencies.
38func (s *Set) List() []Dependency {
39	s.RLock()
40	defer s.RUnlock()
41	r := make([]Dependency, len(s.list))
42	for i, k := range s.list {
43		r[i] = s.set[k]
44	}
45	return r
46}
47
48// Len is the size of the set.
49func (s *Set) Len() int {
50	s.RLock()
51	defer s.RUnlock()
52	return len(s.list)
53}
54
55// String is a string representation of the set.
56func (s *Set) String() string {
57	s.RLock()
58	defer s.RUnlock()
59	return strings.Join(s.list, ", ")
60}
61
62func (s *Set) init() {
63	s.once.Do(func() {
64		if s.list == nil {
65			s.list = make([]string, 0, 8)
66		}
67
68		if s.set == nil {
69			s.set = make(map[string]Dependency)
70		}
71	})
72}
73