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 }