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 notDotChars = [ ] rune { '\n' }
var LBRACKET rune = 0xF0000
var RBRACKET rune = 0xF0001
var ANY_CHAR rune = 0xF0002 // Represents any character - used for 'dot' metacharacter
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 {
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
}