summary refs log tree commit diff stats
path: root/lib/system/iterators.nim
blob: dafd56cb39298524d8a85c2e16903400e16fc4e4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
iterator items*[T](a: openArray[T]): T {.inline.} =
  ## Iterates over each item of `a`.
  var i = 0
  while i < len(a):
    yield a[i]
    inc(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]
    inc(i)

iterator items*[IX, T](a: array[IX, T]): T {.inline.} =
  ## Iterates over each item of `a`.
  var i = low(IX)
  if i <= high(IX):
    while true:
      yield a[i]
      if i >= high(IX): break
      inc(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.
  var i = low(IX)
  if i <= high(IX):
    while true:
      yield a[i]
      if i >= high(IX): break
      inc(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:
    if T(i) in a: yield T(i)
    inc(i)

iterator items*(a: cstring): char {.inline.} =
  ## Iterates over each item of `a`.
  when defined(js):
    var i = 0
    var L = len(a)
    while i < L:
      yield a[i]
      inc(i)
  else:
    var i = 0
    while a[i] != '\0':
      yield a[i]
      inc(i)

iterator mitems*(a: var cstring): var char {.inline.} =
  ## Iterates over each item of `a` so that you can modify the yielded value.
  when defined(js):
    var i = 0
    var L = len(a)
    while i < L:
      yield a[i]
      inc(i)
  else:
    var i = 0
    while a[i] != '\0':
      yield a[i]
      inc(i)

iterator items*(E: typedesc[enum]): E =
  ## Iterates over the values of the enum ``E``.
  for v in low(E) .. high(E):
    yield v

iterator items*[T](s: HSlice[T, 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])
    inc(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])
    inc(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.
  var i = low(IX)
  if i <= high(IX):
    while true:
      yield (i, a[i])
      if i >= high(IX): break
      inc(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.
  var i = low(IX)
  if i <= high(IX):
    while true:
      yield (i, a[i])
      if i >= high(IX): break
      inc(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])
    inc(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])
    inc(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])
    inc(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])
    inc(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])
      inc(i)
  else:
    var i = 0
    while a[i] != '\0':
      yield (i, a[i])
      inc(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])
      inc(i)
  else:
    var i = 0
    while a[i] != '\0':
      yield (i, a[i])
      inc(i)


iterator items*[T](a: seq[T]): T {.inline.} =
  ## Iterates over each item of `a`.
  var i = 0
  let L = len(a)
  while i < L:
    yield a[i]
    inc(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]
    inc(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]
    inc(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]
    inc(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.
iterator fields*[S:tuple|object, T:tuple|object](x: S, y: T): tuple[a,b: untyped] {.
  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.
iterator fieldPairs*[T: tuple|object](x: T): 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>`_. Example:
  ##
  ## .. code-block:: Nim
  ##   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:
  ##         if value.isNil:
  ##           result.add("\n\t" & name & " (nil)")
  ##         else:
  ##           result.add("\n\t" & name & " '" & value & "'")
  ##
  ## 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.

iterator fieldPairs*[S: tuple|object, T: tuple|object](x: S, y: T): tuple[
  a, b: untyped] {.
  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.