// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). // All rights reserved. // list-iterator.go package expr import ( "fmt" "io" ) type ListIterator struct { a *ListType count int index int start int stop int step int } func NewListIterator(list *ListType, args []any) (it *ListIterator) { var argc int = 0 listLen := len(([]any)(*list)) if args != nil { argc = len(args) } it = &ListIterator{a: list, count: 0, index: -1, start: 0, stop: listLen - 1, step: 1} if argc >= 1 { if i, err := ToGoInt(args[0], "start index"); err == nil { if i < 0 { i = listLen + i } it.start = i } if argc >= 2 { if i, err := ToGoInt(args[1], "stop index"); err == nil { if i < 0 { i = listLen + i } it.stop = i } if argc >= 3 { if i, err := ToGoInt(args[2], "step"); err == nil { if i < 0 { i = -i } if it.start > it.stop { it.step = -i } else { it.step = i } } } } } it.index = it.start - it.step return } func NewArrayIterator(array []any) (it *ListIterator) { it = &ListIterator{a: (*ListType)(&array), count: 0, index: -1, start: 0, stop: len(array) - 1, step: 1} return } func NewAnyIterator(value any) (it *ListIterator) { if value == nil { it = NewArrayIterator([]any{}) } else if list, ok := value.(*ListType); ok { it = NewListIterator(list, nil) } else if array, ok := value.([]any); ok { it = NewArrayIterator(array) } else if it1, ok := value.(*ListIterator); ok { it = it1 } else { it = NewArrayIterator([]any{value}) } return } func (it *ListIterator) String() string { var l = 0 if it.a != nil { l = len(*it.a) } return fmt.Sprintf("$(#%d)", l) } func (it *ListIterator) TypeName() string { return "ListIterator" } func (it *ListIterator) HasOperation(name string) bool { yes := name == NextName || name == ResetName || name == IndexName || name == CountName || name == CurrentName return yes } func (it *ListIterator) CallOperation(name string, args []any) (v any, err error) { switch name { case NextName: v, err = it.Next() case ResetName: v, err = it.Reset() case IndexName: v = int64(it.Index()) case CurrentName: v, err = it.Current() case CountName: v = it.count default: err = errNoOperation(name) } return } func (it *ListIterator) Current() (item any, err error) { a := *(it.a) if it.start <= it.stop { if it.stop < len(a) && it.index >= it.start && it.index <= it.stop { item = a[it.index] } else { err = io.EOF } } else { if it.start < len(a) && it.index >= it.stop && it.index <= it.start { item = a[it.index] } else { err = io.EOF } } return } func (it *ListIterator) Next() (item any, err error) { it.index += it.step if item, err = it.Current(); err != io.EOF { it.count++ } return } func (it *ListIterator) Index() int { return it.index } func (it *ListIterator) Reset() (bool, error) { it.index = it.start - it.step return true, nil }