iterators.nim 11 KB

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