diff options
author | Timothee Cour <timothee.cour2@gmail.com> | 2018-11-22 02:47:14 -0800 |
---|---|---|
committer | Arne Döring <arne.doering@gmx.net> | 2018-11-22 11:47:14 +0100 |
commit | 02351d02e752173b3ef168e1e113d6bdbf4a593d (patch) | |
tree | 625d284433b17eadaece9ed855dd14f2e147d4c6 /lib/pure/collections/sequtils.nim | |
parent | 086676782a6053158cc6da14bc65961205c4b014 (diff) | |
download | Nim-02351d02e752173b3ef168e1e113d6bdbf4a593d.tar.gz |
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
Diffstat (limited to 'lib/pure/collections/sequtils.nim')
-rw-r--r-- | lib/pure/collections/sequtils.nim | 160 |
1 files changed, 130 insertions, 30 deletions
diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index e8ea675f5..be10780ff 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -504,36 +504,76 @@ template anyIt*(s, pred: untyped): bool = break result -template toSeq*(iter: untyped): untyped = - ## Transforms any iterator into a sequence. - ## - ## Example: - ## - ## .. 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): +template toSeq1(s: not iterator): untyped = + # overload for typed but not iterator + type outType = type(items(s)) + when compiles(s.len): block: - evalOnceAs(iter2, iter, true) - var result = newSeq[type(iter)](iter2.len) + evalOnceAs(s2, s, compiles((let _ = s))) var i = 0 - for x in iter2: - result[i] = x - inc i + var result = newSeq[outType](s2.len) + for it in s2: + result[i] = it + i += 1 result else: - var result: seq[type(iter)] = @[] - for x in iter: - result.add(x) + var result: seq[outType] = @[] + for it in s: + result.add(it) + 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 to fold a sequence from left to right, returning the accumulation. ## @@ -1033,12 +1073,72 @@ when isMainModule: assert anyIt(anumbers, it > 9) == false block: # toSeq test - 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] + 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] + + 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: # tests https://github.com/nim-lang/Nim/issues/7187 |