package aoc import ( "bufio" "bytes" "context" "io" "iter" ) func SplitComma(data []byte, atEOF bool) (advance int, token []byte, err error) { if atEOF && len(data) == 0 { return 0, nil, nil } if i := bytes.IndexByte(data, ','); i >= 0 { return i + 1, data[0:i], nil } if atEOF { return len(data), data, nil } return 0, nil, nil } func SplitString(s string) bufio.SplitFunc { sep := []byte(s) return func(data []byte, atEOF bool) (advance int, token []byte, err error) { if atEOF && len(data) == 0 { return 0, nil, nil } if i := bytes.Index(data, sep); i >= 0 { return i + len(sep), data[0:i], nil } if atEOF { return len(data), data, nil } return 0, nil, nil } } func ReadString(r io.Reader) (string, error) { buff, err := io.ReadAll(r) if err != nil { return "", err } return string(buff), nil } type Logger interface { Printf(string, ...interface{}) Println(...interface{}) } type Context struct { Body io.Reader Logger Logger Context context.Context } func (c *Context) Scanner(split ...bufio.SplitFunc) *bufio.Scanner { s := bufio.NewScanner(c.Body) if len(split) == 1 { s.Split(split[0]) } if len(split) > 2 { panic("too many split line handlers") } return s } func (c *Context) BodyString() (string, error) { return ReadString(c.Body) } func (c *Context) BodyBytes() ([]byte, error) { return io.ReadAll(c.Body) } func (c *Context) Printf(format string, args ...interface{}) { if c.Logger != nil { c.Logger.Printf(format, args...) } } func (c *Context) Println(args ...interface{}) { if c.Logger != nil { c.Logger.Println(args...) } } type CustomScanner[T scannable, K any] struct { val K err error inner scannable mapFunc func(T) (K, error) } func (s *CustomScanner[T, K]) From(t T) { s.inner = t } func (s *CustomScanner[T, K]) MapFunc(f func(t T) (K, error)) { s.mapFunc = f } func (s *CustomScanner[T, K]) Value() K { return s.val } func (s *CustomScanner[T, K]) Values() iter.Seq[K] { return func(yield func(K) bool) { for s.Scan() { if !yield(s.Value()) { return } } } } type scannable interface { Scan() bool } func (s *CustomScanner[T, K]) Scan() bool { if s.err != nil { return false } if !s.inner.Scan() { return false } s.val, s.err = s.mapFunc(s.inner.(T)) if s.err != nil { return false } return true } func (s *CustomScanner[T, K]) Err() error { return s.err } type numeric interface { ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~float32 | ~float64 } func Sum[T numeric](s []T) T { var res T for _, t := range s { res += t } return res } func Prod[T numeric](s []T) T { var res = T(1) for _, t := range s { res *= t } return res }