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  }