From 50ebd7cc580379cc955dbc711ba7773834a2c5fd Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 20 Aug 2018 22:36:21 -0700 Subject: [PATCH 1/3] universal toSeq: works with UFCS; works with inline, closure, and proc iterators, and also non-iterators --- lib/pure/collections/sequtils.nim | 113 +++++++++++++++++++++++++----- 1 file changed, 94 insertions(+), 19 deletions(-) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 2e21786bbd16..9bfe465fbf2d 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -504,8 +504,8 @@ template anyIt*(s, pred: untyped): bool = break result -template toSeq*(iter: untyped): untyped = - ## Transforms any iterator into a sequence. +template toSeq*(s: not iterator): untyped = + ## Transforms any iterable into a sequence. ## ## Example: ## @@ -517,21 +517,42 @@ template toSeq*(iter: untyped): untyped = ## 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): + 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 toSeq*(iter: iterator): untyped = + 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 foldl*(sequence, operation: untyped): untyped = @@ -1027,12 +1048,66 @@ 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():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 Date: Tue, 21 Aug 2018 12:12:40 -0700 Subject: [PATCH 2/3] support all iterables with toSeq --- lib/pure/collections/sequtils.nim | 54 +++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 9bfe465fbf2d..703a31a8fde2 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -504,19 +504,8 @@ template anyIt*(s, pred: untyped): bool = break result -template toSeq*(s: not iterator): untyped = - ## Transforms any iterable 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] - +template toSeq1(s: not iterator): untyped = + # overload for typed but not iterator type outType = type(items(s)) when compiles(s.len): block: @@ -533,7 +522,8 @@ template toSeq*(s: not iterator): untyped = result.add(it) result -template toSeq*(iter: iterator): untyped = +template toSeq2(iter: iterator): untyped = + # overload for iterator evalOnceAs(iter2, iter(), false) when compiles(iter2.len): var i = 0 @@ -555,6 +545,36 @@ template toSeq*(iter: iterator): untyped = result.add(x) result +template toSeq*(iter: untyped): untyped = + ## Transforms any iterable into a sequence. + runnableExamples: + import sugar + let + numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9] + odd_numbers = toSeq(filter(numeric, x => 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. ## @@ -1063,6 +1083,12 @@ when isMainModule: doAssert @[1,2].toSeq == @[1,2] doAssert toSeq(@[1,2]) == @[1,2] + block: + iterator myIter(seed:int):auto= + for i in 0.. Date: Sun, 30 Sep 2018 10:37:37 +0200 Subject: [PATCH 3/3] workaround for #9130 --- lib/pure/collections/sequtils.nim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 703a31a8fde2..8f6c90b12d2f 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -548,10 +548,9 @@ template toSeq2(iter: iterator): untyped = template toSeq*(iter: untyped): untyped = ## Transforms any iterable into a sequence. runnableExamples: - import sugar let numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9] - odd_numbers = toSeq(filter(numeric, x => x mod 2 == 1)) + 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)):