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
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
|
when defined(nimHasLentIterators) and not defined(nimWorkaround14447):
template lent2(T): untyped = lent T
else:
template lent2(T): untyped = T
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]
inc(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]
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`.
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]
inc(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]
inc(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"
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]
inc(i)
when defined(js): impl()
else:
when nimvm: impl()
else:
var i = 0
while a[i] != '\0':
yield a[i]
inc(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])
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]): lent2 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.
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")
|