Files
expr/int-iterator.go
T

155 lines
3.0 KiB
Go

// Copyright (c) 2024-2026 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"
"git.portale-stac.it/go-pkg/expr/types"
"git.portale-stac.it/go-pkg/expr/types/interval"
)
type IntIterator struct {
count int64
index int64
next int64
current any
start int64
stop int64
step int64
}
func NewIntIteratorFromInterval(p *interval.IntervalType) (it *IntIterator, err error) {
b := p.Begin()
e := p.End()
s := p.Step()
if b > e {
s = -s
}
return NewIntIteratorA(b, e, s)
}
func NewIntIteratorA(args ...any) (it *IntIterator, err error) {
return NewIntIterator(args)
}
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 = types.ToGoInt64(args[0], "start index"); err != nil {
return
}
if argc >= 2 {
it.start = it.stop
if it.stop, err = types.ToGoInt64(args[1], "stop index"); err != nil {
return
}
if argc >= 3 {
if it.step, err = types.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) {
return it.current, nil
}
func (it *IntIterator) Next() (item any, err error) {
item = it.next
if it.step > 0 {
if it.next+it.step > it.stop {
err = io.EOF
}
} else if it.next+it.step < it.stop {
err = io.EOF
}
if err == nil {
it.index++
it.count++
it.next += it.step
it.current = item
}
return
}
func (it *IntIterator) Index() int64 {
return it.index
}
func (it *IntIterator) Count() int64 {
return it.count
}
func (it *IntIterator) Reset() error {
it.index = -1
it.next = it.start
it.current = nil
it.count = 0
return nil
}
func (it *IntIterator) Clean() error {
return nil
}