package main import ( "slices" "unicode" ) var whitespaceChars = []rune{' ', '\t', '\n'} var digitChars = []rune{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'} var wordChars = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_") var LBRACKET rune = 0xF0000 var RBRACKET rune = 0xF0001 func dotChars() []rune { // Returns all possible characters represented by the dot metacharacter - this is too tedious to define as a variable, which is why it is a function start := 0x0020 end := 0x007E to_return := make([]rune, (end-start)+1) for i := start; i <= end; i++ { to_return[i-start] = rune(i) } return to_return } // Returns true if str[idx] and str[idx-1] are separated by a word boundary. func isWordBoundary(str []rune, idx int) bool { wbounded := idx == 0 || idx == len(str)-1 || (!slices.Contains(wordChars, str[idx-1]) && slices.Contains(wordChars, str[idx])) || (slices.Contains(wordChars, str[idx-1]) && !slices.Contains(wordChars, str[idx])) return wbounded } func isAlphaNum(c rune) bool { return unicode.IsLetter(c) || unicode.IsNumber(c) } func assert(cond bool) { if cond != true { panic("Assertion Failed") } } func deleteFromSlice[T comparable](slc []T, val T) []T { toReturn := make([]T, 0) for _, v := range slc { if v != val { toReturn = append(toReturn, v) } } return toReturn } // Ensure that the given elements are only appended to the given slice if they // don't already exist. Returns the new slice, and the number of unique items appended. func unique_append[T comparable](slc []T, items ...T) ([]T, int) { num_appended := 0 for _, item := range items { if !slices.Contains(slc, item) { slc = append(slc, item) num_appended++ } } return slc, num_appended } // Returns true only if all the given elements are equal func allEqual[T comparable](items ...T) bool { first := items[0] for _, item := range items { if item != first { return false } } return true } // Returns all elements in slice A that are NOT in slice B func setDifference[T comparable](s1 []T, s2 []T) []T { toReturn := make([]T, 0) for _, val := range s1 { if !slices.Contains(s2, val) { toReturn = append(toReturn, val) } } return toReturn } // Map function - convert a slice of T to a slice of V, based on a function // that maps a T to a V func Map[T, V any](slc []T, fn func(T) V) []V { toReturn := make([]V, len(slc)) for i, val := range slc { toReturn[i] = fn(val) } return toReturn } // Reduce function - reduces a slice of a type into a value of the type, // based on the given function. func Reduce[T any](slc []T, fn func(T, T) T) T { if len(slc) == 0 { panic("Reduce on empty slice.") } for len(slc) > 1 { v1 := slc[0] v2 := slc[1] slc = slc[1:] slc[0] = fn(v1, v2) } return slc[0] }