github.com/haraldrudell/parl@v0.4.176/sets/pointer-set.go (about) 1 /* 2 © 2023–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/) 3 ISC License 4 */ 5 6 package sets 7 8 import ( 9 "github.com/haraldrudell/parl/internal/cyclebreaker" 10 "github.com/haraldrudell/parl/iters" 11 "github.com/haraldrudell/parl/perrors" 12 "github.com/haraldrudell/parl/pfmt" 13 "github.com/haraldrudell/parl/plog" 14 ) 15 16 // PointerSet is a set where pointer-value provides comparable identity 17 type PointerSet[E any] struct { 18 elementMap map[*E]struct{} 19 elements []*E 20 } 21 22 // NewPointerSet returns a set where pointer-value provides comparable identity 23 // - on every process launch, element identity changes 24 func NewPointerSet[E any](elements []*E) (set Set[*E]) { 25 var m = make(map[*E]struct{}, len(elements)) 26 for i, ep := range elements { 27 if ep == nil { 28 panic(perrors.ErrorfPF( 29 "element-pointer cannot be nil:"+ 30 " pointer-type E: %T index: %d", 31 ep, i, 32 )) 33 } 34 if _, ok := m[ep]; ok { 35 panic(perrors.ErrorfPF( 36 "duplicate set-element:"+ 37 " pointer-type E: %T duplicate value: 0x%x"+ 38 " number of added values: %d", 39 ep, cyclebreaker.Uintptr(ep), 40 i, 41 )) 42 } 43 m[ep] = emptyStuct 44 } 45 return &PointerSet[E]{ 46 elementMap: m, 47 elements: elements, 48 } 49 } 50 51 // IsValid returns whether value is part of the set 52 func (s *PointerSet[E]) IsValid(value *E) (isValid bool) { 53 _, isValid = s.elementMap[value] 54 return 55 } 56 57 // Iterator allows iteration over all set elements 58 func (s *PointerSet[E]) Iterator() (iterator iters.Iterator[*E]) { 59 return iters.NewSliceIterator(s.elements) 60 } 61 62 // StringT returns a string representation for an element of this set. 63 // If value is not a valid element, a fmt.Printf value is output like ?'%v' 64 func (s *PointerSet[E]) StringT(value *E) (s2 string) { 65 // StringT is intended to be the String method of a named type implementing set. 66 // if StringT method code would somehow invoke the T.String method again, 67 // this will cause infinite recursion and stack overflow panic. 68 if _, ok := s.elementMap[value]; ok { 69 s2 = pfmt.NoRecurseVPrint(*value) 70 return 71 } 72 s2 = "?‘" + s2 + "’" 73 74 return 75 } 76 77 // Description returns a more elaborate string representation 78 // for an element. Description and StringT may return the same value 79 func (s *PointerSet[E]) Description(value *E) (full string) { 80 81 // type assert to Element with Description method 82 var elementDescription ElementDescription 83 var ok bool 84 if elementDescription, ok = any(value).(ElementDescription); !ok { 85 return // not a full element return 86 } 87 88 full = elementDescription.Description() 89 90 return 91 } 92 93 func (s *PointerSet[E]) String() (s2 string) { 94 var e E 95 s2 = plog.Sprintf("pointerSet_%T:%d", e, len(s.elementMap)) 96 return 97 }