// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). // All rights reserved. // int-iterator.go package expr import ( "fmt" "io" "slices" "git.portale-stac.it/go-pkg/expr/kern" ) type IntIterator struct { count int64 index int64 start int64 stop int64 step int64 } func NewIntIterator(args []any) (it *IntIterator, err error) { var argc int = 0 if args != nil { argc = len(args) } it = &IntIterator{count: 0, index: -1, start: 0, stop: 0, step: 1} if argc >= 1 { if it.stop, err = kern.ToGoInt64(args[0], "start index"); err != nil { return } if argc >= 2 { it.start = it.stop if it.stop, err = kern.ToGoInt64(args[1], "stop index"); err != nil { return } if argc >= 3 { if it.step, err = kern.ToGoInt64(args[2], "step"); err != nil { return } } else if it.start > it.stop { it.step = -1 } } } if it.step == 0 { err = fmt.Errorf("step cannot be zero") return } if it.start < it.stop && it.step < 0 { err = fmt.Errorf("step cannot be negative when start < stop") return } if it.start > it.stop && it.step > 0 { err = fmt.Errorf("step cannot be positive when start > stop") return } it.Reset() return } func (it *IntIterator) String() string { return fmt.Sprintf("$(%d..%d..%d)", it.start, it.stop, it.step) } func (it *IntIterator) TypeName() string { return "IntIterator" } func (it *IntIterator) HasOperation(name string) bool { yes := slices.Contains([]string{kern.NextName, kern.ResetName, kern.IndexName, kern.CountName, kern.CurrentName}, name) return yes } func (it *IntIterator) CallOperation(name string, args map[string]any) (v any, err error) { switch name { case kern.NextName: v, err = it.Next() case kern.ResetName: err = it.Reset() case kern.CleanName: err = it.Clean() case kern.IndexName: v = int64(it.Index()) case kern.CurrentName: v, err = it.Current() case kern.CountName: v = it.count default: err = kern.ErrNoOperation(name) } return } func (it *IntIterator) Current() (item any, err error) { if it.start <= it.stop { if it.index >= it.start && it.index < it.stop { item = it.index } else { err = io.EOF } } else { if it.index > it.stop && it.index <= it.start { item = it.index } else { err = io.EOF } } return } func (it *IntIterator) Next() (item any, err error) { it.index += it.step if item, err = it.Current(); err != io.EOF { it.count++ } return } func (it *IntIterator) Index() int64 { return it.index } func (it *IntIterator) Count() int64 { return it.count } func (it *IntIterator) Reset() error { it.index = it.start - it.step it.count = 0 return nil } func (it *IntIterator) Clean() error { return nil }