iterators.nim 11 KB

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