github.com/haraldrudell/parl@v0.4.176/pslices/ordered-any.go (about)

     1  /*
     2  © 2022–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/)
     3  ISC License
     4  */
     5  
     6  package pslices
     7  
     8  import (
     9  	"github.com/haraldrudell/parl/parli"
    10  	"github.com/haraldrudell/parl/perrors"
    11  	"golang.org/x/exp/slices"
    12  )
    13  
    14  // OrderedAny is a slice ordered by a function allowing duplicates.
    15  // OrderedAny implements [parl.Ordered][E any].
    16  //   - cmp allows for custom ordering or ordering of slice map and function types
    17  //   - Use E as value for small-sized data or interface values.
    18  //   - Use E as a pointer for larger sized structs.
    19  //   - Duplicates are allowed, Inssert places duplicates at end
    20  //   - Insert and Delete O(log n)
    21  //   - cmp(a, b) is expected to return an integer comparing the two parameters:
    22  //     0 if a == b, a negative number if a < b and a positive number if a > b
    23  type OrderedAny[E any] struct {
    24  	Slice[E] // Element() Length() List() Clear()
    25  	// cmp is a comparison function returning <0 if a<b, 0 if a == b and 1 otherwise.
    26  	// if cmp is nil, order is based on comparison of values
    27  	cmp func(a, b E) (result int)
    28  }
    29  
    30  // NewOrderedAny creates a list ordered by a comparison function.
    31  //   - The cmp comparison function can be provided by E being pslices.Comparable,
    32  //     ie. a type having a Cmp method.
    33  //   - cmp(a, b) is expected to return an integer comparing the two parameters:
    34  //     0 if a == b, a negative number if a < b and a positive number if a > b
    35  //   - duplicate values are allowed and inserted in order with later values last
    36  //   - if E is an interface-type and cmp is nil, every provided value must be checked
    37  //     to be comparable
    38  func NewOrderedAny[E any](cmp func(a, b E) (result int)) (list parli.Ordered[E]) {
    39  	if cmp == nil {
    40  		panic(perrors.NewPF("cmp cannot be nil"))
    41  	}
    42  	return &OrderedAny[E]{cmp: cmp}
    43  }
    44  
    45  // Insert adds a value to the ordered slice.
    46  func (o *OrderedAny[E]) Insert(element E) {
    47  	o.list = InsertOrderedFunc(o.list, element, o.cmp)
    48  }
    49  
    50  // Delete removes an element from the ordered slice.
    51  //   - if the element did not exist, the slice is not changed
    52  //   - if element exists in duplicates, a random element of those duplicates is removed
    53  //   - O(log n)
    54  func (o *OrderedAny[E]) Delete(element E) {
    55  	if position, wasFound := slices.BinarySearchFunc(o.list, element, o.cmp); wasFound {
    56  		o.list = slices.Delete(o.list, position, position+1)
    57  	}
    58  }
    59  
    60  func (o *OrderedAny[E]) Index(element E) (index int) {
    61  	var wasFound bool
    62  	if index, wasFound = slices.BinarySearchFunc(o.list, element, o.cmp); !wasFound {
    63  		index = -1
    64  	}
    65  	return
    66  }
    67  
    68  // Length returns the number of elements
    69  func (o *OrderedAny[E]) Clone() (o2 parli.Ordered[E]) {
    70  	return &OrderedAny[E]{
    71  		Slice: Slice[E]{list: slices.Clone(o.list)},
    72  		cmp:   o.cmp,
    73  	}
    74  }