iterators.nim 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. when defined(nimHasLentIterators) and not defined(nimWorkaround14447):
  2. template lent2(T): untyped = lent T
  3. else:
  4. template lent2(T): untyped = T
  5. iterator items*[T: not char](a: openArray[T]): lent2 T {.inline.} =
  6. ## Iterates over each item of `a`.
  7. var i = 0
  8. while i < len(a):
  9. yield a[i]
  10. inc(i)
  11. iterator items*[T: char](a: openArray[T]): T {.inline.} =
  12. ## Iterates over each item of `a`.
  13. # a VM bug currently prevents taking address of openArray[char]
  14. # elements converted from a string (would fail in `tests/misc/thallo.nim`)
  15. # in any case there's no performance advantage of returning char by address.
  16. var i = 0
  17. while i < len(a):
  18. yield a[i]
  19. inc(i)
  20. iterator mitems*[T](a: var openArray[T]): var T {.inline.} =
  21. ## Iterates over each item of `a` so that you can modify the yielded value.
  22. var i = 0
  23. while i < len(a):
  24. yield a[i]
  25. inc(i)
  26. iterator items*[IX, T](a: array[IX, T]): T {.inline.} =
  27. ## Iterates over each item of `a`.
  28. when a.len > 0:
  29. var i = low(IX)
  30. while true:
  31. yield a[i]
  32. if i >= high(IX): break
  33. inc(i)
  34. iterator mitems*[IX, T](a: var array[IX, T]): var T {.inline.} =
  35. ## Iterates over each item of `a` so that you can modify the yielded value.
  36. when a.len > 0:
  37. var i = low(IX)
  38. while true:
  39. yield a[i]
  40. if i >= high(IX): break
  41. inc(i)
  42. iterator items*[T](a: set[T]): T {.inline.} =
  43. ## Iterates over each element of `a`. `items` iterates only over the
  44. ## elements that are really in the set (and not over the ones the set is
  45. ## able to hold).
  46. var i = low(T).int
  47. while i <= high(T).int:
  48. if T(i) in a: yield T(i)
  49. inc(i)
  50. iterator items*(a: cstring): char {.inline.} =
  51. ## Iterates over each item of `a`.
  52. runnableExamples:
  53. from std/sequtils import toSeq
  54. assert toSeq("abc\0def".cstring) == @['a', 'b', 'c']
  55. assert toSeq("abc".cstring) == @['a', 'b', 'c']
  56. #[
  57. assert toSeq(nil.cstring) == @[] # xxx fails with SIGSEGV
  58. this fails with SIGSEGV; unclear whether we want to instead yield nothing
  59. or pay a small price to check for `nil`, a benchmark is needed. Note that
  60. other procs support `nil`.
  61. ]#
  62. template impl() =
  63. var i = 0
  64. let n = len(a)
  65. while i < n:
  66. yield a[i]
  67. inc(i)
  68. when defined(js): impl()
  69. else:
  70. when nimvm:
  71. # xxx `cstring` should behave like c backend instead.
  72. impl()
  73. else:
  74. var i = 0
  75. while a[i] != '\0':
  76. yield a[i]
  77. inc(i)
  78. iterator mitems*(a: var cstring): var char {.inline.} =
  79. ## Iterates over each item of `a` so that you can modify the yielded value.
  80. # xxx this should give CT error in js RT.
  81. runnableExamples:
  82. from std/sugar import collect
  83. var a = "abc\0def"
  84. var b = a.cstring
  85. let s = collect:
  86. for bi in mitems(b):
  87. if bi == 'b': bi = 'B'
  88. bi
  89. assert s == @['a', 'B', 'c']
  90. assert b == "aBc"
  91. assert a == "aBc\0def"
  92. template impl() =
  93. var i = 0
  94. let n = len(a)
  95. while i < n:
  96. yield a[i]
  97. inc(i)
  98. when defined(js): impl()
  99. else:
  100. when nimvm: impl()
  101. else:
  102. var i = 0
  103. while a[i] != '\0':
  104. yield a[i]
  105. inc(i)
  106. iterator items*[T: enum and Ordinal](E: typedesc[T]): T =
  107. ## Iterates over the values of `E`.
  108. ## See also `enumutils.items` for enums with holes.
  109. runnableExamples:
  110. type Goo = enum g0 = 2, g1, g2
  111. from std/sequtils import toSeq
  112. assert Goo.toSeq == [g0, g1, g2]
  113. for v in low(E) .. high(E):
  114. yield v
  115. iterator items*[T: Ordinal](s: Slice[T]): T =
  116. ## Iterates over the slice `s`, yielding each value between `s.a` and `s.b`
  117. ## (inclusively).
  118. for x in s.a .. s.b:
  119. yield x
  120. iterator pairs*[T](a: openArray[T]): tuple[key: int, val: T] {.inline.} =
  121. ## Iterates over each item of `a`. Yields `(index, a[index])` pairs.
  122. var i = 0
  123. while i < len(a):
  124. yield (i, a[i])
  125. inc(i)
  126. iterator mpairs*[T](a: var openArray[T]): tuple[key: int, val: var T]{.inline.} =
  127. ## Iterates over each item of `a`. Yields `(index, a[index])` pairs.
  128. ## `a[index]` can be modified.
  129. var i = 0
  130. while i < len(a):
  131. yield (i, a[i])
  132. inc(i)
  133. iterator pairs*[IX, T](a: array[IX, T]): tuple[key: IX, val: T] {.inline.} =
  134. ## Iterates over each item of `a`. Yields `(index, a[index])` pairs.
  135. when a.len > 0:
  136. var i = low(IX)
  137. while true:
  138. yield (i, a[i])
  139. if i >= high(IX): break
  140. inc(i)
  141. iterator mpairs*[IX, T](a: var array[IX, T]): tuple[key: IX, val: var T] {.inline.} =
  142. ## Iterates over each item of `a`. Yields `(index, a[index])` pairs.
  143. ## `a[index]` can be modified.
  144. when a.len > 0:
  145. var i = low(IX)
  146. while true:
  147. yield (i, a[i])
  148. if i >= high(IX): break
  149. inc(i)
  150. iterator pairs*[T](a: seq[T]): tuple[key: int, val: T] {.inline.} =
  151. ## Iterates over each item of `a`. Yields `(index, a[index])` pairs.
  152. var i = 0
  153. let L = len(a)
  154. while i < L:
  155. yield (i, a[i])
  156. inc(i)
  157. assert(len(a) == L, "the length of the seq changed while iterating over it")
  158. iterator mpairs*[T](a: var seq[T]): tuple[key: int, val: var T] {.inline.} =
  159. ## Iterates over each item of `a`. Yields `(index, a[index])` pairs.
  160. ## `a[index]` can be modified.
  161. var i = 0
  162. let L = len(a)
  163. while i < L:
  164. yield (i, a[i])
  165. inc(i)
  166. assert(len(a) == L, "the length of the seq changed while iterating over it")
  167. iterator pairs*(a: string): tuple[key: int, val: char] {.inline.} =
  168. ## Iterates over each item of `a`. Yields `(index, a[index])` pairs.
  169. var i = 0
  170. let L = len(a)
  171. while i < L:
  172. yield (i, a[i])
  173. inc(i)
  174. assert(len(a) == L, "the length of the string changed while iterating over it")
  175. iterator mpairs*(a: var string): tuple[key: int, val: var char] {.inline.} =
  176. ## Iterates over each item of `a`. Yields `(index, a[index])` pairs.
  177. ## `a[index]` can be modified.
  178. var i = 0
  179. let L = len(a)
  180. while i < L:
  181. yield (i, a[i])
  182. inc(i)
  183. assert(len(a) == L, "the length of the string changed while iterating over it")
  184. iterator pairs*(a: cstring): tuple[key: int, val: char] {.inline.} =
  185. ## Iterates over each item of `a`. Yields `(index, a[index])` pairs.
  186. when defined(js):
  187. var i = 0
  188. var L = len(a)
  189. while i < L:
  190. yield (i, a[i])
  191. inc(i)
  192. else:
  193. var i = 0
  194. while a[i] != '\0':
  195. yield (i, a[i])
  196. inc(i)
  197. iterator mpairs*(a: var cstring): tuple[key: int, val: var char] {.inline.} =
  198. ## Iterates over each item of `a`. Yields `(index, a[index])` pairs.
  199. ## `a[index]` can be modified.
  200. when defined(js):
  201. var i = 0
  202. var L = len(a)
  203. while i < L:
  204. yield (i, a[i])
  205. inc(i)
  206. else:
  207. var i = 0
  208. while a[i] != '\0':
  209. yield (i, a[i])
  210. inc(i)
  211. iterator items*[T](a: seq[T]): lent2 T {.inline.} =
  212. ## Iterates over each item of `a`.
  213. var i = 0
  214. let L = len(a)
  215. while i < L:
  216. yield a[i]
  217. inc(i)
  218. assert(len(a) == L, "the length of the seq changed while iterating over it")
  219. iterator mitems*[T](a: var seq[T]): var T {.inline.} =
  220. ## Iterates over each item of `a` so that you can modify the yielded value.
  221. var i = 0
  222. let L = len(a)
  223. while i < L:
  224. yield a[i]
  225. inc(i)
  226. assert(len(a) == L, "the length of the seq changed while iterating over it")
  227. iterator items*(a: string): char {.inline.} =
  228. ## Iterates over each item of `a`.
  229. var i = 0
  230. let L = len(a)
  231. while i < L:
  232. yield a[i]
  233. inc(i)
  234. assert(len(a) == L, "the length of the string changed while iterating over it")
  235. iterator mitems*(a: var string): var char {.inline.} =
  236. ## Iterates over each item of `a` so that you can modify the yielded value.
  237. var i = 0
  238. let L = len(a)
  239. while i < L:
  240. yield a[i]
  241. inc(i)
  242. assert(len(a) == L, "the length of the string changed while iterating over it")
  243. iterator fields*[T: tuple|object](x: T): RootObj {.
  244. magic: "Fields", noSideEffect.} =
  245. ## Iterates over every field of `x`.
  246. ##
  247. ## .. warning:: This really transforms the 'for' and unrolls the loop.
  248. ## The current implementation also has a bug
  249. ## that affects symbol binding in the loop body.
  250. runnableExamples:
  251. var t = (1, "foo")
  252. for v in fields(t): v = default(typeof(v))
  253. doAssert t == (0, "")
  254. iterator fields*[S:tuple|object, T:tuple|object](x: S, y: T): tuple[key: string, val: RootObj] {.
  255. magic: "Fields", noSideEffect.} =
  256. ## Iterates over every field of `x` and `y`.
  257. ##
  258. ## .. warning:: This really transforms the 'for' and unrolls the loop.
  259. ## The current implementation also has a bug that affects symbol binding
  260. ## in the loop body.
  261. runnableExamples:
  262. var t1 = (1, "foo")
  263. var t2 = default(typeof(t1))
  264. for v1, v2 in fields(t1, t2): v2 = v1
  265. doAssert t1 == t2
  266. iterator fieldPairs*[T: tuple|object](x: T): tuple[key: string, val: RootObj] {.
  267. magic: "FieldPairs", noSideEffect.} =
  268. ## Iterates over every field of `x` returning their name and value.
  269. ##
  270. ## When you iterate over objects with different field types you have to use
  271. ## the compile time `when` instead of a runtime `if` to select the code
  272. ## you want to run for each type. To perform the comparison use the `is
  273. ## operator <manual.html#generics-is-operator>`_.
  274. ## Another way to do the same without `when` is to leave the task of
  275. ## picking the appropriate code to a secondary proc which you overload for
  276. ## each field type and pass the `value` to.
  277. ##
  278. ## .. warning:: This really transforms the 'for' and unrolls the loop. The
  279. ## current implementation also has a bug that affects symbol binding in the
  280. ## loop body.
  281. runnableExamples:
  282. type
  283. Custom = object
  284. foo: string
  285. bar: bool
  286. proc `$`(x: Custom): string =
  287. result = "Custom:"
  288. for name, value in x.fieldPairs:
  289. when value is bool:
  290. result.add("\n\t" & name & " is " & $value)
  291. else:
  292. result.add("\n\t" & name & " '" & value & "'")
  293. iterator fieldPairs*[S: tuple|object, T: tuple|object](x: S, y: T): tuple[
  294. key: string, a, b: RootObj] {.
  295. magic: "FieldPairs", noSideEffect.} =
  296. ## Iterates over every field of `x` and `y`.
  297. ##
  298. ## .. warning:: This really transforms the 'for' and unrolls the loop.
  299. ## The current implementation also has a bug that affects symbol binding
  300. ## in the loop body.
  301. runnableExamples:
  302. type Foo = object
  303. x1: int
  304. x2: string
  305. var a1 = Foo(x1: 12, x2: "abc")
  306. var a2: Foo
  307. for name, v1, v2 in fieldPairs(a1, a2):
  308. when name == "x2": v2 = v1
  309. doAssert a2 == Foo(x1: 0, x2: "abc")