github.com/haraldrudell/parl@v0.4.176/sets/map-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 "slices" 11 12 "github.com/haraldrudell/parl/iters" 13 "github.com/haraldrudell/parl/pfmt" 14 "github.com/haraldrudell/parl/plog" 15 "golang.org/x/exp/constraints" 16 ) 17 18 type MapSet[T constraints.Ordered, E any] struct { 19 elementMap map[T]E 20 elements []sorter[T, E] 21 } 22 23 type sorter[T constraints.Ordered, E any] struct { 24 t T 25 e E 26 } 27 28 func NewMapSet[T constraints.Ordered, E any](m map[T]E) (set SetID[T, E]) { 29 30 // sort elements 31 // - no pointers is 1 allocation 32 var sortable = make([]sorter[T, E], len(m)) 33 var i int 34 for t, e := range m { 35 sortable[i] = sorter[T, E]{t: t, e: e} 36 i++ 37 } 38 slices.SortFunc(sortable, sorterCmp[T, E]) 39 40 return &MapSet[T, E]{ 41 elementMap: m, 42 elements: sortable, 43 } 44 } 45 46 // IsValid returns whether value is part of the set 47 func (s *MapSet[T, E]) IsValid(value T) (isValid bool) { 48 _, isValid = s.elementMap[value] 49 return 50 } 51 52 // Iterator allows iteration over all set elements 53 func (s *MapSet[T, E]) Iterator() (iterator iters.Iterator[T]) { 54 return iters.NewSimpleConverterIterator( 55 iters.NewSlicePointerIterator(s.elements), 56 s.convertT, 57 ) 58 } 59 60 // StringT returns a string representation for an element of this set. 61 // If value is not a valid element, a fmt.Printf value is output like ?'%v' 62 func (s *MapSet[T, E]) StringT(value T) (s2 string) { 63 var e, ok = s.elementMap[value] 64 if !ok { 65 s2 = fmt.Sprintf("?badID‘%v’", value) 66 return 67 } 68 // StringT is intended to be the String method of a named type implementing set. 69 // if StringT method code would somehow invoke the T.String method again, 70 // this will cause infinite recursion and stack overflow panic. 71 s2 = pfmt.NoRecurseVPrint(e) 72 73 return 74 } 75 76 // Description returns a more elaborate string representation 77 // for an element. Description and StringT may return the same value 78 func (s *MapSet[T, E]) Description(value T) (full string) { 79 var e, ok = s.elementMap[value] 80 if !ok { 81 return 82 } 83 // type assert to Element with Description method 84 var elementFull ElementDescription 85 if elementFull, ok = any(&e).(ElementDescription); !ok { 86 return // not a full element return 87 } 88 89 full = elementFull.Description() 90 91 return 92 } 93 94 // Element returns the element representation for value or 95 // nil if value is not an element of the set 96 func (s *MapSet[T, E]) Element(value T) (elementType *E) { 97 var e, ok = s.elementMap[value] 98 if !ok { 99 return 100 } 101 elementType = &e 102 103 return 104 } 105 106 // Iterator allows iteration over all set elements 107 func (s *MapSet[T, E]) EIterator() (iterator iters.Iterator[*E]) { 108 return iters.NewSimpleConverterIterator( 109 iters.NewSlicePointerIterator(s.elements), 110 s.convertE, 111 ) 112 113 } 114 115 func (s *MapSet[T, E]) convertT(tePair *sorter[T, E]) (value T) { return tePair.t } 116 117 func (s *MapSet[T, E]) convertE(tePair *sorter[T, E]) (elementType *E) { return &tePair.e } 118 119 func (s *MapSet[T, E]) String() (s2 string) { 120 var e E 121 s2 = plog.Sprintf("mapSet_%T:%d", e, len(s.elementMap)) 122 return 123 } 124 125 func sorterCmp[T constraints.Ordered, E any](a, b sorter[T, E]) (result int) { 126 if a.t < b.t { 127 return -1 128 } else if a.t > b.t { 129 return 1 130 } 131 return 132 }