2025-01-11 00:25:52 +01:00

148 lines
3.8 KiB
GDScript

extends IteratorBase
class_name Iterator
## A naive iterator with additional quality-of-life utility
##
## See [IteratorBase] and [IterableBase] for more info!
## Loops over all elements within the iterable sequence
func foreach(what : Callable = func(__elem): pass):
var next_ = self.next()
while not next_ is ItEnd:
var continue_ = what.call(next_)
if continue_ == false:
break
next_ = self.next()
## Loops and enumerates an iterable sequence
func enumerate(what : Callable = func(__elem, __idx : int): pass):
var idx_ = 0
var next_ = self.next()
while not next_ is ItEnd:
var continue_ = what.call(next_, idx_)
if continue_ == false:
break
idx_ += 1
next_ = self.next()
## An iterable working on an [Array] or a relative like [PackedByteArray]
class ArrayIterable extends IterableBase:
var _x
var _start : int
var _end : int
func _init(x, start : int = 0, end : int = -1):
self._x = x
self._start = start
self._end = x.size() if end < 0 else end
if self._start < 0 or self._start > self._end or self._end > x.size():
ArgumentOutOfRangeError.raise()
return
class _Iterator extends Iterator:
var _itx
var _itstart : int
var _itend : int
var _itindex : int
func _init(x, start : int, end : int):
self._itx = x
self._itstart = start
self._itend = end
self._itindex = start
func has_next() -> bool:
return not (self._itx.is_empty() or self._itindex == self._itend)
func next() -> Variant:
if not has_next():
return ItEnd.new()
self._itindex += 1
return self._itx[self._itindex - 1]
func front() -> Variant:
return ItEnd.new() if self._itx.is_empty() else self._itx[self._itstart]
func back() -> Variant:
return ItEnd.new() if self._itx.is_empty() else self._itx[self._itend - 1]
func empty() -> bool:
return self._itx.is_empty()
func at(n : int) -> Variant:
var it = _Iterator.new(self._itx, self._itstart, self._itend)
var tmp = ItEnd.new()
for i in range(n):
tmp = it.next()
return tmp
func iter() -> Iterator:
return self._Iterator.new(self._x, self._start, self._end)
## An iterable working on a [Dictionary]
class DictionaryIterable extends IterableBase:
var _dict : Dictionary
func _init(dict : Dictionary):
self._dict = dict
class _Iterator extends Iterator:
var _itdict : Dictionary
var _itindex : int
var _itend : int
var _itkeys : Array
func _init(dict : Dictionary):
self._itdict = dict
self._itindex = 0
self._itend = dict.size()
self._itkeys = dict.keys()
func has_next() -> bool:
return not (self._itdict.is_empty() or self._itindex == self._itend)
func next() -> Variant:
if not has_next():
return ItEnd.new()
self._itindex += 1
return Tuple.new([
self._itkeys[self._itindex - 1],
self._itdict[self._itkeys[self._itindex - 1]]
])
func empty() -> bool:
return self._itdict.is_empty()
func iter() -> Iterator:
return self._Iterator.new(self._dict)
## Anonymous [IterableBase]
class _Iterable extends IterableBase:
var seq
func _init(seq_):
self.seq = seq_
func iter() -> Iterator:
return seq.iter()
## Constructs an iterable sequence of type [IterableBase] based on x.
static func to_iterable(x : Variant) -> IterableBase:
if x is Array or x is PackedByteArray or x is PackedColorArray or x is PackedFloat32Array or x is PackedFloat64Array or x is PackedInt32Array or x is PackedInt64Array or x is PackedStringArray or x is PackedVector2Array or x is PackedVector3Array:
return ArrayIterable.new(x)
if x is Dictionary:
return DictionaryIterable.new(x)
if x is IterableBase:
return x
if x.has_method("iter"):
return _Iterable.new(x)
return to_iterable([x])
## Returns an [Iterator] onto the given sequence.
static func iter(x) -> Iterator:
return to_iterable(x).iter()