// Package aghalgo contains common generic algorithms and data structures. // // TODO(a.garipov): Update to use type parameters in Go 1.18. package aghalgo import ( "fmt" "sort" ) // comparable is an alias for interface{}. Values passed as arguments of this // type alias must be comparable. // // TODO(a.garipov): Remove in Go 1.18. type comparable = interface{} // UniquenessValidator allows validating uniqueness of comparable items. type UniquenessValidator map[comparable]int64 // Add adds a value to the validator. v must not be nil. func (v UniquenessValidator) Add(elems ...comparable) { for _, e := range elems { v[e]++ } } // Merge returns a validator containing data from both v and other. func (v UniquenessValidator) Merge(other UniquenessValidator) (merged UniquenessValidator) { merged = make(UniquenessValidator, len(v)+len(other)) for elem, num := range v { merged[elem] += num } for elem, num := range other { merged[elem] += num } return merged } // Validate returns an error enumerating all elements that aren't unique. // isBefore is an optional sorting function to make the error message // deterministic. func (v UniquenessValidator) Validate(isBefore func(a, b comparable) (less bool)) (err error) { var dup []comparable for elem, num := range v { if num > 1 { dup = append(dup, elem) } } if len(dup) == 0 { return nil } if isBefore != nil { sort.Slice(dup, func(i, j int) (less bool) { return isBefore(dup[i], dup[j]) }) } return fmt.Errorf("duplicated values: %v", dup) } // IntIsBefore is a helper sort function for UniquenessValidator.Validate. // a and b must be of type int. func IntIsBefore(a, b comparable) (less bool) { return a.(int) < b.(int) } // StringIsBefore is a helper sort function for UniquenessValidator.Validate. // a and b must be of type string. func StringIsBefore(a, b comparable) (less bool) { return a.(string) < b.(string) }