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  }