github.com/haraldrudell/parl@v0.4.176/sets/func-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 "fmt" 10 11 "github.com/haraldrudell/parl/internal/cyclebreaker" 12 "github.com/haraldrudell/parl/iters" 13 "github.com/haraldrudell/parl/perrors" 14 "github.com/haraldrudell/parl/pfmt" 15 "github.com/haraldrudell/parl/plog" 16 ) 17 18 // FuncSet is a set where a function eIDFunc extracts element ID from elements 19 type FuncSet[T comparable, E any] struct { 20 elementMap map[T]*E 21 elements []E 22 ts []T 23 eIDFunc func(elementType *E) (elementID T) 24 } 25 26 // NewFunctionSet returns a set where a function eIDFunc extracts element ID from elements 27 func NewFunctionSet[T comparable, E any](elements []E, eIDFunc func(elementType *E) (elementID T)) (set SetID[T, E]) { 28 if eIDFunc == nil { 29 cyclebreaker.NilError("eIDFunc") 30 } 31 var m = make(map[T]*E, len(elements)) 32 var ts = make([]T, len(elements)) 33 for i := 0; i < len(elements); i++ { 34 var ep = &elements[i] 35 var t = eIDFunc(ep) 36 if _, ok := m[t]; ok { 37 var e E 38 panic(perrors.ErrorfPF( 39 "duplicate set-element:"+ 40 " type T: %T duplicate value: ‘%[1]v’"+ 41 " type E: %T duplicate value: ‘%s’"+ 42 " number of added values: %d", 43 t, 44 e, pfmt.NoRecurseVPrint(e), 45 i, 46 )) 47 } 48 m[t] = ep 49 ts[i] = t 50 } 51 return &FuncSet[T, E]{ 52 elementMap: m, 53 elements: elements, 54 ts: ts, 55 eIDFunc: eIDFunc, 56 } 57 } 58 59 // IsValid returns whether value is part of the set 60 func (s *FuncSet[T, E]) IsValid(value T) (isValid bool) { 61 _, isValid = s.elementMap[value] 62 return 63 } 64 65 // Iterator allows iteration over all set elements 66 func (s *FuncSet[T, E]) Iterator() (iterator iters.Iterator[T]) { return iters.NewSliceIterator(s.ts) } 67 68 // StringT returns a string representation for an element of this set. 69 // If value is not a valid element, a fmt.Printf value is output like ?'%v' 70 func (s *FuncSet[T, E]) StringT(value T) (s2 string) { 71 var ep, isValid = s.elementMap[value] 72 if stringer, ok := any(ep).(fmt.Stringer); ok { 73 s2 = stringer.String() 74 } else { 75 s2 = fmt.Sprintf("%v", *ep) 76 } 77 if isValid { 78 return 79 } 80 s2 = fmt.Sprintf("?badID‘%v’", value) 81 82 return 83 } 84 85 // Description returns a more elaborate string representation 86 // for an element. Description and StringT may return the same value 87 func (s *FuncSet[T, E]) Description(value T) (full string) { 88 var ep, ok = s.elementMap[value] 89 if !ok { 90 return 91 } 92 93 // type assert to Element with Description method 94 var elementDescription ElementDescription 95 if elementDescription, ok = any(ep).(ElementDescription); !ok { 96 return // not a full element return 97 } 98 99 full = elementDescription.Description() 100 101 return 102 } 103 104 // Element returns the element representation for value or 105 // nil if value is not an element of the set 106 func (s *FuncSet[T, E]) Element(value T) (elementType *E) { return s.elementMap[value] } 107 108 // Iterator allows iteration over all set elements 109 func (s *FuncSet[T, E]) EIterator() (iterator iters.Iterator[*E]) { 110 return iters.NewSlicePointerIterator(s.elements) 111 } 112 113 func (s *FuncSet[T, E]) String() (s2 string) { 114 var e E 115 s2 = plog.Sprintf("funcSet_%T:%d", e, len(s.elementMap)) 116 return 117 }