123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354 |
- ## Default iterators for some Nim types.
- when defined(nimPreviewSlimSystem):
- import std/assertions
- when not defined(nimNoLentIterators):
- template lent2(T): untyped = lent T
- else:
- template lent2(T): untyped = T
- template unCheckedInc(x) =
- {.push overflowChecks: off.}
- inc(x)
- {.pop.}
- iterator items*[T: not char](a: openArray[T]): lent2 T {.inline.} =
- ## Iterates over each item of `a`.
- var i = 0
- while i < len(a):
- yield a[i]
- unCheckedInc(i)
- iterator items*[T: char](a: openArray[T]): T {.inline.} =
- ## Iterates over each item of `a`.
- # a VM bug currently prevents taking address of openArray[char]
- # elements converted from a string (would fail in `tests/misc/thallo.nim`)
- # in any case there's no performance advantage of returning char by address.
- var i = 0
- while i < len(a):
- yield a[i]
- unCheckedInc(i)
- iterator mitems*[T](a: var openArray[T]): var T {.inline.} =
- ## Iterates over each item of `a` so that you can modify the yielded value.
- var i = 0
- while i < len(a):
- yield a[i]
- unCheckedInc(i)
- iterator items*[IX, T](a: array[IX, T]): T {.inline.} =
- ## Iterates over each item of `a`.
- when a.len > 0:
- var i = low(IX)
- while true:
- yield a[i]
- if i >= high(IX): break
- unCheckedInc(i)
- iterator mitems*[IX, T](a: var array[IX, T]): var T {.inline.} =
- ## Iterates over each item of `a` so that you can modify the yielded value.
- when a.len > 0:
- var i = low(IX)
- while true:
- yield a[i]
- if i >= high(IX): break
- unCheckedInc(i)
- iterator items*[T](a: set[T]): T {.inline.} =
- ## Iterates over each element of `a`. `items` iterates only over the
- ## elements that are really in the set (and not over the ones the set is
- ## able to hold).
- var i = low(T).int
- while i <= high(T).int:
- when T is enum and not defined(js):
- if cast[T](i) in a: yield cast[T](i)
- else:
- if T(i) in a: yield T(i)
- unCheckedInc(i)
- iterator items*(a: cstring): char {.inline.} =
- ## Iterates over each item of `a`.
- runnableExamples:
- from std/sequtils import toSeq
- assert toSeq("abc\0def".cstring) == @['a', 'b', 'c']
- assert toSeq("abc".cstring) == @['a', 'b', 'c']
- #[
- assert toSeq(nil.cstring) == @[] # xxx fails with SIGSEGV
- this fails with SIGSEGV; unclear whether we want to instead yield nothing
- or pay a small price to check for `nil`, a benchmark is needed. Note that
- other procs support `nil`.
- ]#
- template impl() =
- var i = 0
- let n = len(a)
- while i < n:
- yield a[i]
- unCheckedInc(i)
- when defined(js): impl()
- else:
- when nimvm:
- # xxx `cstring` should behave like c backend instead.
- impl()
- else:
- var i = 0
- while a[i] != '\0':
- yield a[i]
- unCheckedInc(i)
- iterator mitems*(a: var cstring): var char {.inline.} =
- ## Iterates over each item of `a` so that you can modify the yielded value.
- # xxx this should give CT error in js RT.
- runnableExamples:
- from std/sugar import collect
- var a = "abc\0def"
- prepareMutation(a)
- var b = a.cstring
- let s = collect:
- for bi in mitems(b):
- if bi == 'b': bi = 'B'
- bi
- assert s == @['a', 'B', 'c']
- assert b == "aBc"
- assert a == "aBc\0def"
- template impl() =
- var i = 0
- let n = len(a)
- while i < n:
- yield a[i]
- unCheckedInc(i)
- when defined(js): impl()
- else:
- when nimvm: impl()
- else:
- var i = 0
- while a[i] != '\0':
- yield a[i]
- unCheckedInc(i)
- iterator items*[T: enum and Ordinal](E: typedesc[T]): T =
- ## Iterates over the values of `E`.
- ## See also `enumutils.items` for enums with holes.
- runnableExamples:
- type Goo = enum g0 = 2, g1, g2
- from std/sequtils import toSeq
- assert Goo.toSeq == [g0, g1, g2]
- for v in low(E) .. high(E):
- yield v
- iterator items*[T: Ordinal](s: Slice[T]): T =
- ## Iterates over the slice `s`, yielding each value between `s.a` and `s.b`
- ## (inclusively).
- for x in s.a .. s.b:
- yield x
- iterator pairs*[T](a: openArray[T]): tuple[key: int, val: T] {.inline.} =
- ## Iterates over each item of `a`. Yields `(index, a[index])` pairs.
- var i = 0
- while i < len(a):
- yield (i, a[i])
- unCheckedInc(i)
- iterator mpairs*[T](a: var openArray[T]): tuple[key: int, val: var T]{.inline.} =
- ## Iterates over each item of `a`. Yields `(index, a[index])` pairs.
- ## `a[index]` can be modified.
- var i = 0
- while i < len(a):
- yield (i, a[i])
- unCheckedInc(i)
- iterator pairs*[IX, T](a: array[IX, T]): tuple[key: IX, val: T] {.inline.} =
- ## Iterates over each item of `a`. Yields `(index, a[index])` pairs.
- when a.len > 0:
- var i = low(IX)
- while true:
- yield (i, a[i])
- if i >= high(IX): break
- unCheckedInc(i)
- iterator mpairs*[IX, T](a: var array[IX, T]): tuple[key: IX, val: var T] {.inline.} =
- ## Iterates over each item of `a`. Yields `(index, a[index])` pairs.
- ## `a[index]` can be modified.
- when a.len > 0:
- var i = low(IX)
- while true:
- yield (i, a[i])
- if i >= high(IX): break
- unCheckedInc(i)
- iterator pairs*[T](a: seq[T]): tuple[key: int, val: T] {.inline.} =
- ## Iterates over each item of `a`. Yields `(index, a[index])` pairs.
- var i = 0
- let L = len(a)
- while i < L:
- yield (i, a[i])
- unCheckedInc(i)
- assert(len(a) == L, "the length of the seq changed while iterating over it")
- iterator mpairs*[T](a: var seq[T]): tuple[key: int, val: var T] {.inline.} =
- ## Iterates over each item of `a`. Yields `(index, a[index])` pairs.
- ## `a[index]` can be modified.
- var i = 0
- let L = len(a)
- while i < L:
- yield (i, a[i])
- unCheckedInc(i)
- assert(len(a) == L, "the length of the seq changed while iterating over it")
- iterator pairs*(a: string): tuple[key: int, val: char] {.inline.} =
- ## Iterates over each item of `a`. Yields `(index, a[index])` pairs.
- var i = 0
- let L = len(a)
- while i < L:
- yield (i, a[i])
- unCheckedInc(i)
- assert(len(a) == L, "the length of the string changed while iterating over it")
- iterator mpairs*(a: var string): tuple[key: int, val: var char] {.inline.} =
- ## Iterates over each item of `a`. Yields `(index, a[index])` pairs.
- ## `a[index]` can be modified.
- var i = 0
- let L = len(a)
- while i < L:
- yield (i, a[i])
- unCheckedInc(i)
- assert(len(a) == L, "the length of the string changed while iterating over it")
- iterator pairs*(a: cstring): tuple[key: int, val: char] {.inline.} =
- ## Iterates over each item of `a`. Yields `(index, a[index])` pairs.
- when defined(js):
- var i = 0
- var L = len(a)
- while i < L:
- yield (i, a[i])
- unCheckedInc(i)
- else:
- var i = 0
- while a[i] != '\0':
- yield (i, a[i])
- unCheckedInc(i)
- iterator mpairs*(a: var cstring): tuple[key: int, val: var char] {.inline.} =
- ## Iterates over each item of `a`. Yields `(index, a[index])` pairs.
- ## `a[index]` can be modified.
- when defined(js):
- var i = 0
- var L = len(a)
- while i < L:
- yield (i, a[i])
- unCheckedInc(i)
- else:
- var i = 0
- while a[i] != '\0':
- yield (i, a[i])
- unCheckedInc(i)
- iterator items*[T](a: seq[T]): lent2 T {.inline.} =
- ## Iterates over each item of `a`.
- var i = 0
- let L = len(a)
- while i < L:
- yield a[i]
- unCheckedInc(i)
- assert(len(a) == L, "the length of the seq changed while iterating over it")
- iterator mitems*[T](a: var seq[T]): var T {.inline.} =
- ## Iterates over each item of `a` so that you can modify the yielded value.
- var i = 0
- let L = len(a)
- while i < L:
- yield a[i]
- unCheckedInc(i)
- assert(len(a) == L, "the length of the seq changed while iterating over it")
- iterator items*(a: string): char {.inline.} =
- ## Iterates over each item of `a`.
- var i = 0
- let L = len(a)
- while i < L:
- yield a[i]
- unCheckedInc(i)
- assert(len(a) == L, "the length of the string changed while iterating over it")
- iterator mitems*(a: var string): var char {.inline.} =
- ## Iterates over each item of `a` so that you can modify the yielded value.
- var i = 0
- let L = len(a)
- while i < L:
- yield a[i]
- unCheckedInc(i)
- assert(len(a) == L, "the length of the string changed while iterating over it")
- iterator fields*[T: tuple|object](x: T): RootObj {.
- magic: "Fields", noSideEffect.} =
- ## Iterates over every field of `x`.
- ##
- ## .. warning:: This really transforms the 'for' and unrolls the loop.
- ## The current implementation also has a bug
- ## that affects symbol binding in the loop body.
- runnableExamples:
- var t = (1, "foo")
- for v in fields(t): v = default(typeof(v))
- doAssert t == (0, "")
- iterator fields*[S:tuple|object, T:tuple|object](x: S, y: T): tuple[key: string, val: RootObj] {.
- magic: "Fields", noSideEffect.} =
- ## Iterates over every field of `x` and `y`.
- ##
- ## .. warning:: This really transforms the 'for' and unrolls the loop.
- ## The current implementation also has a bug that affects symbol binding
- ## in the loop body.
- runnableExamples:
- var t1 = (1, "foo")
- var t2 = default(typeof(t1))
- for v1, v2 in fields(t1, t2): v2 = v1
- doAssert t1 == t2
- iterator fieldPairs*[T: tuple|object](x: T): tuple[key: string, val: RootObj] {.
- magic: "FieldPairs", noSideEffect.} =
- ## Iterates over every field of `x` returning their name and value.
- ##
- ## When you iterate over objects with different field types you have to use
- ## the compile time `when` instead of a runtime `if` to select the code
- ## you want to run for each type. To perform the comparison use the `is
- ## operator <manual.html#generics-is-operator>`_.
- ## Another way to do the same without `when` is to leave the task of
- ## picking the appropriate code to a secondary proc which you overload for
- ## each field type and pass the `value` to.
- ##
- ## .. warning:: This really transforms the 'for' and unrolls the loop. The
- ## current implementation also has a bug that affects symbol binding in the
- ## loop body.
- runnableExamples:
- type
- Custom = object
- foo: string
- bar: bool
- proc `$`(x: Custom): string =
- result = "Custom:"
- for name, value in x.fieldPairs:
- when value is bool:
- result.add("\n\t" & name & " is " & $value)
- else:
- result.add("\n\t" & name & " '" & value & "'")
- iterator fieldPairs*[S: tuple|object, T: tuple|object](x: S, y: T): tuple[
- key: string, a, b: RootObj] {.
- magic: "FieldPairs", noSideEffect.} =
- ## Iterates over every field of `x` and `y`.
- ##
- ## .. warning:: This really transforms the 'for' and unrolls the loop.
- ## The current implementation also has a bug that affects symbol binding
- ## in the loop body.
- runnableExamples:
- type Foo = object
- x1: int
- x2: string
- var a1 = Foo(x1: 12, x2: "abc")
- var a2: Foo
- for name, v1, v2 in fieldPairs(a1, a2):
- when name == "x2": v2 = v1
- doAssert a2 == Foo(x1: 0, x2: "abc")
|