diff options
Diffstat (limited to 'lib/pure/collections/sequtils.nim')
-rw-r--r-- | lib/pure/collections/sequtils.nim | 182 |
1 files changed, 148 insertions, 34 deletions
diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 2e21786bb..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. ## @@ -673,10 +713,16 @@ template mapIt*(s: typed, op: untyped): untyped = ## nums = @[1, 2, 3, 4] ## strings = nums.mapIt($(4 * it)) ## assert strings == @["4", "8", "12", "16"] - type outType = type(( - block: - var it{.inject.}: type(items(s)); - op)) + when defined(nimHasTypeof): + type outType = typeof(( + block: + var it{.inject.}: typeof(items(s), typeOfIter); + op), typeOfProc) + else: + type outType = type(( + block: + var it{.inject.}: type(items(s)); + op)) when compiles(s.len): block: # using a block avoids https://github.com/nim-lang/Nim/issues/8580 @@ -1027,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 @@ -1135,5 +1241,13 @@ when isMainModule: A, B doAssert mapIt(X, $it) == @["A", "B"] + block: + # bug #9093 + let inp = "a:b,c:d" + + let outp = inp.split(",").mapIt(it.split(":")) + doAssert outp == @[@["a", "b"], @["c", "d"]] + + when not defined(testing): echo "Finished doc tests" |