diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim
index 2770a3950f..095775cbbb 100644
--- a/lib/pure/collections/lists.nim
+++ b/lib/pure/collections/lists.nim
@@ -122,6 +122,22 @@ iterator items*[T](L: DoublyLinkedRing[T]): T =
## yields every value of `L`.
itemsRingImpl()
+iterator mitems*[T](L: var DoublyLinkedList[T]): var T =
+ ## yields every value of `L` so that you can modify it.
+ itemsListImpl()
+
+iterator mitems*[T](L: var SinglyLinkedList[T]): var T =
+ ## yields every value of `L` so that you can modify it.
+ itemsListImpl()
+
+iterator mitems*[T](L: var SinglyLinkedRing[T]): var T =
+ ## yields every value of `L` so that you can modify it.
+ itemsRingImpl()
+
+iterator mitems*[T](L: var DoublyLinkedRing[T]): var T =
+ ## yields every value of `L` so that you can modify it.
+ itemsRingImpl()
+
iterator nodes*[T](L: SinglyLinkedList[T]): SinglyLinkedNode[T] =
## iterates over every node of `x`. Removing the current node from the
## list during traversal is supported.
diff --git a/lib/pure/collections/queues.nim b/lib/pure/collections/queues.nim
index fb4d35310a..af5e7b6cd7 100644
--- a/lib/pure/collections/queues.nim
+++ b/lib/pure/collections/queues.nim
@@ -39,6 +39,15 @@ iterator items*[T](q: Queue[T]): T =
yield q.data[i]
i = (i + 1) and q.mask
+iterator mitems*[T](q: var Queue[T]): var T =
+ ## yields every element of `q`.
+ var i = q.rd
+ var c = q.count
+ while c > 0:
+ dec c
+ yield q.data[i]
+ i = (i + 1) and q.mask
+
proc add*[T](q: var Queue[T], item: T) =
## adds an `item` to the end of the queue `q`.
var cap = q.mask+1
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index 733516bea2..873e4b78ee 100644
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -872,12 +872,26 @@ iterator items*(node: JsonNode): JsonNode =
for i in items(node.elems):
yield i
+iterator mitems*(node: var JsonNode): var JsonNode =
+ ## Iterator for the items of `node`. `node` has to be a JArray. Items can be
+ ## modified.
+ assert node.kind == JArray
+ for i in mitems(node.elems):
+ yield i
+
iterator pairs*(node: JsonNode): tuple[key: string, val: JsonNode] =
## Iterator for the child elements of `node`. `node` has to be a JObject.
assert node.kind == JObject
for key, val in items(node.fields):
yield (key, val)
+iterator mpairs*(node: var JsonNode): var tuple[key: string, val: JsonNode] =
+ ## Iterator for the child elements of `node`. `node` has to be a JObject.
+ ## Items can be modified
+ assert node.kind == JObject
+ for keyVal in mitems(node.fields):
+ yield keyVal
+
proc eat(p: var JsonParser, tok: TTokKind) =
if p.tok == tok: discard getTok(p)
else: raiseParseErr(p, tokToStr[tok])
diff --git a/lib/pure/poly.nim b/lib/pure/poly.nim
index 286e5a8fda..58dcdc1ad7 100644
--- a/lib/pure/poly.nim
+++ b/lib/pure/poly.nim
@@ -58,7 +58,7 @@ proc `[]=` *(p:var Poly;idx:int,v:float)=
iterator items*(p:Poly):float=
- ## Iterates through the corfficients of the polynomial.
+ ## Iterates through the coefficients of the polynomial.
var i=p.degree
while i>=0:
yield p[i]
diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim
index 3c789d841c..c783158ea5 100644
--- a/lib/pure/xmltree.nim
+++ b/lib/pure/xmltree.nim
@@ -115,11 +115,21 @@ proc `[]`* (n: XmlNode, i: int): XmlNode {.inline.} =
assert n.k == xnElement
result = n.s[i]
+proc mget* (n: var XmlNode, i: int): var XmlNode {.inline.} =
+ ## returns the `i`'th child of `n` so that it can be modified
+ assert n.k == xnElement
+ result = n.s[i]
+
iterator items*(n: XmlNode): XmlNode {.inline.} =
## iterates over any child of `n`.
assert n.k == xnElement
for i in 0 .. n.len-1: yield n[i]
+iterator mitems*(n: var XmlNode): var XmlNode {.inline.} =
+ ## iterates over any child of `n`.
+ assert n.k == xnElement
+ for i in 0 .. n.len-1: yield mget(n, i)
+
proc attrs*(n: XmlNode): XmlAttributes {.inline.} =
## gets the attributes belonging to `n`.
## Returns `nil` if attributes have not been initialised for this node.
diff --git a/lib/system.nim b/lib/system.nim
index 69a77b89b6..12c5c63036 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -1653,6 +1653,13 @@ iterator items*[T](a: openArray[T]): T {.inline.} =
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)
@@ -1662,6 +1669,15 @@ iterator items*[IX, T](a: array[IX, T]): T {.inline.} =
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
@@ -1680,6 +1696,13 @@ iterator items*(a: cstring): char {.inline.} =
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.
+ 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):
@@ -1692,6 +1715,14 @@ iterator pairs*[T](a: openArray[T]): tuple[key: int, val: T] {.inline.} =
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)
@@ -1701,6 +1732,16 @@ iterator pairs*[IX, T](a: array[IX, T]): tuple[key: IX, val: T] {.inline.} =
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
@@ -1708,6 +1749,14 @@ iterator pairs*[T](a: seq[T]): tuple[key: int, val: T] {.inline.} =
yield (i, a[i])
inc(i)
+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
+ while i < len(a):
+ yield (i, a[i])
+ inc(i)
+
iterator pairs*(a: string): tuple[key: int, val: char] {.inline.} =
## iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
var i = 0
@@ -1715,6 +1764,29 @@ iterator pairs*(a: string): tuple[key: int, val: char] {.inline.} =
yield (i, a[i])
inc(i)
+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
+ while i < len(a):
+ yield (i, a[i])
+ inc(i)
+
+iterator pairs*(a: cstring): tuple[key: int, val: char] {.inline.} =
+ ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
+ 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.
+ var i = 0
+ while a[i] != '\0':
+ yield (i, a[i])
+ inc(i)
+
proc isNil*[T](x: seq[T]): bool {.noSideEffect, magic: "IsNil".}
proc isNil*[T](x: ref T): bool {.noSideEffect, magic: "IsNil".}
@@ -2992,6 +3064,15 @@ iterator items*[T](a: seq[T]): T {.inline.} =
inc(i)
assert(len(a) == L, "seq modified 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, "seq modified while iterating over it")
+
iterator items*(a: string): char {.inline.} =
## iterates over each item of `a`.
var i = 0
@@ -3001,6 +3082,15 @@ iterator items*(a: string): char {.inline.} =
inc(i)
assert(len(a) == L, "string modified 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, "string modified while iterating over it")
+
when not defined(nimhygiene):
{.pragma: inject.}
diff --git a/tests/stdlib/tmitems.nim b/tests/stdlib/tmitems.nim
new file mode 100644
index 0000000000..2297f0ee93
--- /dev/null
+++ b/tests/stdlib/tmitems.nim
@@ -0,0 +1,136 @@
+discard """
+ output: '''@[11, 12, 13]
+@[11, 12, 13]
+@[1, 3, 5]
+@[1, 3, 5]
+gppcbs
+gppcbs
+fpqeew
+fpqeew
+[11, 12, 13]
+[11, 12, 13]
+[11, 12, 13]
+[11, 12, 13]
+{ "key1": 11, "key2": 12, "key3": 13}
+[ 11, 12, 13]
+
+
+
+'''
+"""
+
+block:
+ var xs = @[1,2,3]
+ for x in xs.mitems:
+ x += 10
+ echo xs
+
+block:
+ var xs = [1,2,3]
+ for x in xs.mitems:
+ x += 10
+ echo(@xs)
+
+block:
+ var xs = @[1,2,3]
+ for i, x in xs.mpairs:
+ x += i
+ echo xs
+
+block:
+ var xs = [1,2,3]
+ for i, x in xs.mpairs:
+ x += i
+ echo(@xs)
+
+block:
+ var x = "foobar"
+ for c in x.mitems:
+ inc c
+ echo x
+
+block:
+ var x = "foobar"
+ var y = cast[cstring](addr x[0])
+ for c in y.mitems:
+ inc c
+ echo x
+
+block:
+ var x = "foobar"
+ for i, c in x.mpairs:
+ inc c, i
+ echo x
+
+block:
+ var x = "foobar"
+ var y = cast[cstring](addr x[0])
+ for i, c in y.mpairs:
+ inc c, i
+ echo x
+
+import lists
+
+block:
+ var sl = initSinglyLinkedList[int]()
+ sl.prepend(3)
+ sl.prepend(2)
+ sl.prepend(1)
+ for x in sl.mitems:
+ x += 10
+ echo sl
+
+block:
+ var sl = initDoublyLinkedList[int]()
+ sl.append(1)
+ sl.append(2)
+ sl.append(3)
+ for x in sl.mitems:
+ x += 10
+ echo sl
+
+block:
+ var sl = initDoublyLinkedRing[int]()
+ sl.append(1)
+ sl.append(2)
+ sl.append(3)
+ for x in sl.mitems:
+ x += 10
+ echo sl
+
+import queues
+
+block:
+ var q = initQueue[int]()
+ q.add(1)
+ q.add(2)
+ q.add(3)
+ for x in q.mitems:
+ x += 10
+ echo q
+
+import json
+
+block:
+ var j = parseJson """{"key1": 1, "key2": 2, "key3": 3}"""
+ for key,val in j.pairs:
+ val.num += 10
+ echo j
+
+block:
+ var j = parseJson """[1, 2, 3]"""
+ for x in j.mitems:
+ x.num += 10
+ echo j
+
+import xmltree, xmlparser, streams, strtabs
+
+block:
+ var d = parseXml(newStringStream """
+
+
+ """)
+ for x in d.mitems:
+ x = <>Student(Name=x.attrs["Name"] & "foo")
+ d.mget(1).attrs["Name"] = "bar"
+ echo d