universal toSeq: works with UFCS; works with inline & closure iterators, and with iterables (#8711)
* universal toSeq: works with UFCS; works with inline, closure, and proc iterators, and also non-iterators * support all iterables with toSeq * workaround for #9130
This commit is contained in:
parent
086676782a
commit
02351d02e7
1 changed files with 130 additions and 30 deletions
|
|
@ -504,36 +504,76 @@ template anyIt*(s, pred: untyped): bool =
|
||||||
break
|
break
|
||||||
result
|
result
|
||||||
|
|
||||||
template toSeq*(iter: untyped): untyped =
|
template toSeq1(s: not iterator): untyped =
|
||||||
## Transforms any iterator into a sequence.
|
# overload for typed but not iterator
|
||||||
##
|
type outType = type(items(s))
|
||||||
## Example:
|
when compiles(s.len):
|
||||||
##
|
|
||||||
## .. code-block::
|
|
||||||
## let
|
|
||||||
## numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
||||||
## odd_numbers = toSeq(filter(numeric) do (x: int) -> bool:
|
|
||||||
## if x mod 2 == 1:
|
|
||||||
## result = true)
|
|
||||||
## assert odd_numbers == @[1, 3, 5, 7, 9]
|
|
||||||
|
|
||||||
# Note: see also `mapIt` for explanation of some of the implementation
|
|
||||||
# subtleties.
|
|
||||||
when compiles(iter.len):
|
|
||||||
block:
|
block:
|
||||||
evalOnceAs(iter2, iter, true)
|
evalOnceAs(s2, s, compiles((let _ = s)))
|
||||||
var result = newSeq[type(iter)](iter2.len)
|
|
||||||
var i = 0
|
var i = 0
|
||||||
for x in iter2:
|
var result = newSeq[outType](s2.len)
|
||||||
result[i] = x
|
for it in s2:
|
||||||
inc i
|
result[i] = it
|
||||||
|
i += 1
|
||||||
result
|
result
|
||||||
else:
|
else:
|
||||||
var result: seq[type(iter)] = @[]
|
var result: seq[outType] = @[]
|
||||||
for x in iter:
|
for it in s:
|
||||||
result.add(x)
|
result.add(it)
|
||||||
result
|
result
|
||||||
|
|
||||||
|
template toSeq2(iter: iterator): untyped =
|
||||||
|
# overload for iterator
|
||||||
|
evalOnceAs(iter2, iter(), false)
|
||||||
|
when compiles(iter2.len):
|
||||||
|
var i = 0
|
||||||
|
var result = newSeq[type(iter2)](iter2.len)
|
||||||
|
for x in iter2:
|
||||||
|
result[i] = x
|
||||||
|
inc i
|
||||||
|
result
|
||||||
|
else:
|
||||||
|
type outType = type(iter2())
|
||||||
|
var result: seq[outType] = @[]
|
||||||
|
when compiles(iter2()):
|
||||||
|
evalOnceAs(iter4, iter, false)
|
||||||
|
let iter3=iter4()
|
||||||
|
for x in iter3():
|
||||||
|
result.add(x)
|
||||||
|
else:
|
||||||
|
for x in iter2():
|
||||||
|
result.add(x)
|
||||||
|
result
|
||||||
|
|
||||||
|
template toSeq*(iter: untyped): untyped =
|
||||||
|
## Transforms any iterable into a sequence.
|
||||||
|
runnableExamples:
|
||||||
|
let
|
||||||
|
numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||||
|
odd_numbers = toSeq(filter(numeric, proc(x: int): bool = x mod 2 == 1))
|
||||||
|
doAssert odd_numbers == @[1, 3, 5, 7, 9]
|
||||||
|
|
||||||
|
when compiles(toSeq1(iter)):
|
||||||
|
toSeq1(iter)
|
||||||
|
elif compiles(toSeq2(iter)):
|
||||||
|
toSeq2(iter)
|
||||||
|
else:
|
||||||
|
# overload for untyped, eg: `toSeq(myInlineIterator(3))`
|
||||||
|
when compiles(iter.len):
|
||||||
|
block:
|
||||||
|
evalOnceAs(iter2, iter, true)
|
||||||
|
var result = newSeq[type(iter)](iter2.len)
|
||||||
|
var i = 0
|
||||||
|
for x in iter2:
|
||||||
|
result[i] = x
|
||||||
|
inc i
|
||||||
|
result
|
||||||
|
else:
|
||||||
|
var result: seq[type(iter)] = @[]
|
||||||
|
for x in iter:
|
||||||
|
result.add(x)
|
||||||
|
result
|
||||||
|
|
||||||
template foldl*(sequence, operation: untyped): untyped =
|
template foldl*(sequence, operation: untyped): untyped =
|
||||||
## Template to fold a sequence from left to right, returning the accumulation.
|
## Template to fold a sequence from left to right, returning the accumulation.
|
||||||
##
|
##
|
||||||
|
|
@ -1033,12 +1073,72 @@ when isMainModule:
|
||||||
assert anyIt(anumbers, it > 9) == false
|
assert anyIt(anumbers, it > 9) == false
|
||||||
|
|
||||||
block: # toSeq test
|
block: # toSeq test
|
||||||
let
|
block:
|
||||||
numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
|
let
|
||||||
odd_numbers = toSeq(filter(numeric) do (x: int) -> bool:
|
numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||||
if x mod 2 == 1:
|
odd_numbers = toSeq(filter(numeric) do (x: int) -> bool:
|
||||||
result = true)
|
if x mod 2 == 1:
|
||||||
assert odd_numbers == @[1, 3, 5, 7, 9]
|
result = true)
|
||||||
|
assert odd_numbers == @[1, 3, 5, 7, 9]
|
||||||
|
|
||||||
|
block:
|
||||||
|
doAssert [1,2].toSeq == @[1,2]
|
||||||
|
doAssert @[1,2].toSeq == @[1,2]
|
||||||
|
|
||||||
|
doAssert @[1,2].toSeq == @[1,2]
|
||||||
|
doAssert toSeq(@[1,2]) == @[1,2]
|
||||||
|
|
||||||
|
block:
|
||||||
|
iterator myIter(seed:int):auto=
|
||||||
|
for i in 0..<seed:
|
||||||
|
yield i
|
||||||
|
doAssert toSeq(myIter(2)) == @[0, 1]
|
||||||
|
|
||||||
|
block:
|
||||||
|
iterator myIter():auto{.inline.}=
|
||||||
|
yield 1
|
||||||
|
yield 2
|
||||||
|
|
||||||
|
doAssert myIter.toSeq == @[1,2]
|
||||||
|
doAssert toSeq(myIter) == @[1,2]
|
||||||
|
|
||||||
|
block:
|
||||||
|
iterator myIter():int {.closure.} =
|
||||||
|
yield 1
|
||||||
|
yield 2
|
||||||
|
|
||||||
|
doAssert myIter.toSeq == @[1,2]
|
||||||
|
doAssert toSeq(myIter) == @[1,2]
|
||||||
|
|
||||||
|
block:
|
||||||
|
proc myIter():auto=
|
||||||
|
iterator ret():int{.closure.}=
|
||||||
|
yield 1
|
||||||
|
yield 2
|
||||||
|
result = ret
|
||||||
|
|
||||||
|
doAssert myIter().toSeq == @[1,2]
|
||||||
|
doAssert toSeq(myIter()) == @[1,2]
|
||||||
|
|
||||||
|
block:
|
||||||
|
proc myIter(n:int):auto=
|
||||||
|
var counter = 0
|
||||||
|
iterator ret():int{.closure.}=
|
||||||
|
while counter<n:
|
||||||
|
yield counter
|
||||||
|
counter.inc
|
||||||
|
result = ret
|
||||||
|
|
||||||
|
block:
|
||||||
|
let myIter3 = myIter(3)
|
||||||
|
doAssert myIter3.toSeq == @[0,1,2]
|
||||||
|
block:
|
||||||
|
let myIter3 = myIter(3)
|
||||||
|
doAssert toSeq(myIter3) == @[0,1,2]
|
||||||
|
block:
|
||||||
|
# makes sure this does not hang forever
|
||||||
|
doAssert myIter(3).toSeq == @[0,1,2]
|
||||||
|
doAssert toSeq(myIter(3)) == @[0,1,2]
|
||||||
|
|
||||||
block:
|
block:
|
||||||
# tests https://github.com/nim-lang/Nim/issues/7187
|
# tests https://github.com/nim-lang/Nim/issues/7187
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue