|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"slices"
|
|
|
|
)
|
|
|
|
|
|
|
|
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
|
|
|
|
var ANY_CHAR rune = 0xF0002 // Represents any character - used for states where the allChars flag is on.
|
|
|
|
|
|
|
|
// Returns true if str[idx] and str[idx-1] are separated by a word boundary.
|
|
|
|
func isWordBoundary(str []rune, idx int) bool {
|
|
|
|
str_runes := []rune(str)
|
|
|
|
wbounded := idx == 0 ||
|
|
|
|
idx >= len(str) ||
|
|
|
|
(!slices.Contains(wordChars, str_runes[idx-1]) && slices.Contains(wordChars, str_runes[idx])) ||
|
|
|
|
(slices.Contains(wordChars, str_runes[idx-1]) && !slices.Contains(wordChars, str_runes[idx]))
|
|
|
|
return wbounded
|
|
|
|
}
|
|
|
|
|
|
|
|
func isNormalChar(c rune) bool {
|
|
|
|
specialChars := []rune(`?*\^${}()+|[].~`)
|
|
|
|
specialChars = append(specialChars, LBRACKET, RBRACKET)
|
|
|
|
return !slices.Contains(specialChars, c)
|
|
|
|
}
|
|
|
|
|
|
|
|
func assert(cond bool) {
|
|
|
|
if cond != true {
|
|
|
|
panic("Assertion Failed")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func deleteFromSlice[T comparable](slc []T, val T) []T {
|
|
|
|
toReturn := make([]T, 0, len(slc))
|
|
|
|
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, len(s1))
|
|
|
|
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]
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generate numbers in a range - start (inclusive) to end (exclusive)
|
|
|
|
func genRange(start, end int) []int {
|
|
|
|
toRet := make([]int, end-start)
|
|
|
|
for i := start; i < end; i++ {
|
|
|
|
toRet[i-start] = i
|
|
|
|
}
|
|
|
|
return toRet
|
|
|
|
}
|