summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2015-10-12 20:42:17 +0200
committerAndreas Rumpf <rumpf_a@web.de>2015-10-12 20:42:17 +0200
commit7b9d929d50c6eb5a6ebc2fa6cd61b6dcb32a17d9 (patch)
tree020332c6ad754bdbb769cbd21dc01bc8a48d1043
parent9ceeab14f3c96d62da77097c01fb8e6eac3bad9a (diff)
parente2468fee55a3477a5707ac2d74b329fcb73f4f2b (diff)
downloadNim-7b9d929d50c6eb5a6ebc2fa6cd61b6dcb32a17d9.tar.gz
Merge pull request #3423 from petermora/breakSequtils
Break sequtils
-rw-r--r--examples/maximum.nim2
-rw-r--r--lib/pure/collections/sequtils.nim203
-rw-r--r--lib/system.nim47
-rw-r--r--tests/closure/tclosure4.nim2
-rw-r--r--tests/collections/tapply.nim7
-rw-r--r--tests/collections/tmapit.nim28
-rw-r--r--tests/generics/tinferredgenericprocs.nim1
-rw-r--r--tests/generics/tmap_auto.nim2
-rw-r--r--tests/overload/toverprc.nim2
-rw-r--r--tests/parser/tcommand_as_expr.nim1
-rw-r--r--tests/stdlib/tunittest.nim2
-rw-r--r--tests/template/twrongmapit.nim2
-rw-r--r--web/news.txt8
13 files changed, 218 insertions, 89 deletions
diff --git a/examples/maximum.nim b/examples/maximum.nim
index aa3fe375a..6552a8144 100644
--- a/examples/maximum.nim
+++ b/examples/maximum.nim
@@ -1,6 +1,6 @@
 # Test high level features
 
-import strutils
+import strutils, sequtils
 
 echo "Give a list of numbers (separated by spaces): "
 stdin.readLine.split.map(parseInt).max.`$`.echo(" is the maximum!")
diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim
index e6ea19a6b..fd012e811 100644
--- a/lib/pure/collections/sequtils.nim
+++ b/lib/pure/collections/sequtils.nim
@@ -47,7 +47,7 @@ proc concat*[T](seqs: varargs[seq[T]]): seq[T] =
       result[i] = itm
       inc(i)
 
-proc repeat*[T](s: seq[T], n: Natural): seq[T] =
+proc cycle*[T](s: seq[T], n: Natural): seq[T] =
   ## Returns a new sequence with the items of `s` repeated `n` times.
   ##
   ## Example:
@@ -56,15 +56,29 @@ proc repeat*[T](s: seq[T], n: Natural): seq[T] =
   ##
   ##   let
   ##     s = @[1, 2, 3]
-  ##     total = s.repeat(3)
+  ##     total = s.cycle(3)
   ##   assert total == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
   result = newSeq[T](n * s.len)
   var o = 0
-  for x in 1..n:
+  for x in 0..<n:
     for e in s:
       result[o] = e
       inc o
 
+proc repeat*[T](x: T, n: Natural): seq[T] =
+  ## Returns a new sequence with the item `x` repeated `n` times.
+  ##
+  ## Example:
+  ##
+  ## .. code-block:
+  ##
+  ##   let
+  ##     total = repeat(5, 3)
+  ##   assert total == @[5, 5, 5]
+  result = newSeq[T](n)
+  for i in 0..<n:
+    result[i] = x
+
 proc deduplicate*[T](seq1: seq[T]): seq[T] =
   ## Returns a new sequence without duplicates.
   ##
@@ -169,6 +183,77 @@ proc distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] =
       first = last
 
 
+proc map*[T, S](data: openArray[T], op: proc (x: T): S {.closure.}):
+                                                            seq[S]{.inline.} =
+  ## Returns a new sequence with the results of `op` applied to every item in
+  ## `data`.
+  ##
+  ## Since the input is not modified you can use this version of ``map`` to
+  ## transform the type of the elements in the input sequence. Example:
+  ##
+  ## .. code-block:: nim
+  ##   let
+  ##     a = @[1, 2, 3, 4]
+  ##     b = map(a, proc(x: int): string = $x)
+  ##   assert b == @["1", "2", "3", "4"]
+  newSeq(result, data.len)
+  for i in 0..data.len-1: result[i] = op(data[i])
+
+proc map*[T](data: var openArray[T], op: proc (x: var T) {.closure.})
+                                                              {.deprecated.} =
+  ## Applies `op` to every item in `data` modifying it directly.
+  ##
+  ## Note that this version of ``map`` requires your input and output types to
+  ## be the same, since they are modified in-place. Example:
+  ##
+  ## .. code-block:: nim
+  ##   var a = @["1", "2", "3", "4"]
+  ##   echo repr(a)
+  ##   # --> ["1", "2", "3", "4"]
+  ##   map(a, proc(x: var string) = x &= "42")
+  ##   echo repr(a)
+  ##   # --> ["142", "242", "342", "442"]
+  ## **Deprecated since version 0.12.0:** Use the ``apply`` proc instead.
+  for i in 0..data.len-1: op(data[i])
+
+proc apply*[T](data: var seq[T], op: proc (x: var T) {.closure.})
+                                                              {.inline.} =
+  ## Applies `op` to every item in `data` modifying it directly.
+  ##
+  ## Note that this requires your input and output types to
+  ## be the same, since they are modified in-place.
+  ## The parameter function takes a ``var T`` type parameter.
+  ## Example:
+  ##
+  ## .. code-block:: nim
+  ##   var a = @["1", "2", "3", "4"]
+  ##   echo repr(a)
+  ##   # --> ["1", "2", "3", "4"]
+  ##   map(a, proc(x: var string) = x &= "42")
+  ##   echo repr(a)
+  ##   # --> ["142", "242", "342", "442"]
+  ##
+  for i in 0..data.len-1: op(data[i])
+
+proc apply*[T](data: var seq[T], op: proc (x: T): T {.closure.})
+                                                              {.inline.} =
+  ## Applies `op` to every item in `data` modifying it directly.
+  ##
+  ## Note that this requires your input and output types to
+  ## be the same, since they are modified in-place.
+  ## The parameter function takes and returns a ``T`` type variable.
+  ## Example:
+  ##
+  ## .. code-block:: nim
+  ##   var a = @["1", "2", "3", "4"]
+  ##   echo repr(a)
+  ##   # --> ["1", "2", "3", "4"]
+  ##   map(a, proc(x: string): string = x & "42")
+  ##   echo repr(a)
+  ##   # --> ["142", "242", "342", "442"]
+  ##
+  for i in 0..data.len-1: data[i] = op(data[i])
+
 
 iterator filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): T =
   ## Iterates through a sequence and yields every item that fulfills the
@@ -181,11 +266,12 @@ iterator filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): T =
   ##   for n in filter(numbers, proc (x: int): bool = x mod 2 == 0):
   ##     echo($n)
   ##   # echoes 4, 8, 4 in separate lines
-  for i in countup(0, len(seq1)-1):
-    var item = seq1[i]
-    if pred(item): yield seq1[i]
+  for i in 0..<seq1.len:
+    if pred(seq1[i]):
+      yield seq1[i]
 
-proc filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): seq[T] =
+proc filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): seq[T]
+                                                                  {.inline.} =
   ## Returns a new sequence with all the items that fulfilled the predicate.
   ##
   ## Example:
@@ -197,9 +283,13 @@ proc filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): seq[T] =
   ##     f2 = filter(colors) do (x: string) -> bool : x.len > 5
   ##   assert f1 == @["red", "black"]
   ##   assert f2 == @["yellow"]
-  accumulateResult(filter(seq1, pred))
+  result = newSeq[T]()
+  for i in 0..<seq1.len:
+    if pred(seq1[i]):
+      result.add(seq1[i])
 
-proc keepIf*[T](seq1: var seq[T], pred: proc(item: T): bool {.closure.}) =
+proc keepIf*[T](seq1: var seq[T], pred: proc(item: T): bool {.closure.})
+                                                                {.inline.} =
   ## Keeps the items in the passed sequence if they fulfilled the predicate.
   ## Same as the ``filter`` proc, but modifies the sequence directly.
   ##
@@ -213,7 +303,7 @@ proc keepIf*[T](seq1: var seq[T], pred: proc(item: T): bool {.closure.}) =
   for i in 0 .. <len(seq1):
     if pred(seq1[i]):
       if pos != i:
-        seq1[pos] = seq1[i]
+        shallowCopy(seq1[pos], seq1[i])
       inc(pos)
   setLen(seq1, pos)
 
@@ -268,7 +358,7 @@ proc insert*[T](dest: var seq[T], src: openArray[T], pos=0) =
     inc(j)
 
 
-template filterIt*(seq1, pred: expr): expr {.immediate.} =
+template filterIt*(seq1, pred: expr): expr =
   ## Returns a new sequence with all the items that fulfilled the predicate.
   ##
   ## Unlike the `proc` version, the predicate needs to be an expression using
@@ -282,12 +372,12 @@ template filterIt*(seq1, pred: expr): expr {.immediate.} =
   ##      notAcceptable = filterIt(temperatures, it > 50 or it < -10)
   ##    assert acceptable == @[-2.0, 24.5, 44.31]
   ##    assert notAcceptable == @[-272.15, 99.9, -113.44]
-  var result {.gensym.}: type(seq1) = @[]
+  var result {.gensym.} = newSeq[type(seq1[0])]()
   for it {.inject.} in items(seq1):
     if pred: result.add(it)
   result
 
-template keepItIf*(varSeq, pred: expr) =
+template keepItIf*(varSeq: seq, pred: expr) =
   ## Convenience template around the ``keepIf`` proc to reduce typing.
   ##
   ## Unlike the `proc` version, the predicate needs to be an expression using
@@ -303,7 +393,7 @@ template keepItIf*(varSeq, pred: expr) =
     let it {.inject.} = varSeq[i]
     if pred:
       if pos != i:
-        varSeq[pos] = varSeq[i]
+        shallowCopy(varSeq[pos], varSeq[i])
       inc(pos)
   setLen(varSeq, pos)
 
@@ -320,14 +410,19 @@ template toSeq*(iter: expr): expr {.immediate.} =
   ##       if x mod 2 == 1:
   ##         result = true)
   ##   assert odd_numbers == @[1, 3, 5, 7, 9]
-  ##
-  ## **Note**: Since this is an immediate macro, you cannot always invoke this
-  ## as ``x.toSeq``, depending on the ``x``.
-  ## See `this <manual.html#limitations-of-the-method-call-syntax>`_
-  ## for an explanation.
-  var result {.gensym.}: seq[type(iter)] = @[]
-  for x in iter: add(result, x)
-  result
+  
+  when compiles(iter.len):
+    var i = 0
+    var result = newSeq[type(iter)](iter.len)
+    for x in iter:
+      result[i] = x
+      inc i
+    result
+  else:
+    var result: seq[type(iter)] = @[]
+    for x in iter:
+      result.add(x)
+    result
 
 template foldl*(sequence, operation: expr): expr =
   ## Template to fold a sequence from left to right, returning the accumulation.
@@ -358,7 +453,7 @@ template foldl*(sequence, operation: expr): expr =
   assert sequence.len > 0, "Can't fold empty sequences"
   var result {.gensym.}: type(sequence[0])
   result = sequence[0]
-  for i in countup(1, sequence.len - 1):
+  for i in 1..<sequence.len:
     let
       a {.inject.} = result
       b {.inject.} = sequence[i]
@@ -401,7 +496,7 @@ template foldr*(sequence, operation: expr): expr =
     result = operation
   result
 
-template mapIt*(seq1, typ, op: expr): expr =
+template mapIt*(seq1, typ, op: expr): expr {.deprecated.}=
   ## Convenience template around the ``map`` proc to reduce typing.
   ##
   ## The template injects the ``it`` variable which you can use directly in an
@@ -414,13 +509,45 @@ template mapIt*(seq1, typ, op: expr): expr =
   ##     nums = @[1, 2, 3, 4]
   ##     strings = nums.mapIt(string, $(4 * it))
   ##   assert strings == @["4", "8", "12", "16"]
+  ## **Deprecated since version 0.12.0:** Use the ``mapIt(seq1, op)``
+  ##   template instead.
   var result {.gensym.}: seq[typ] = @[]
   for it {.inject.} in items(seq1):
     result.add(op)
   result
 
-template mapIt*(varSeq, op: expr) =
-  ## Convenience template around the mutable ``map`` proc to reduce typing.
+
+template mapIt*(seq1, op: expr): expr =
+  ## Convenience template around the ``map`` proc to reduce typing.
+  ##
+  ## The template injects the ``it`` variable which you can use directly in an
+  ## expression. Example:
+  ##
+  ## .. code-block::
+  ##   let
+  ##     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(seq1));
+      op))
+  var result: seq[outType]
+  when compiles(seq1.len):
+    let s = seq1
+    var i = 0
+    result = newSeq[outType](s.len)
+    for it {.inject.} in s:
+      result[i] = op
+      i += 1
+  else:
+    result = @[]
+    for it {.inject.} in seq1:
+      result.add(op)
+  result
+
+template applyIt*(varSeq, op: expr) =
+  ## Convenience template around the mutable ``apply`` proc to reduce typing.
   ##
   ## The template injects the ``it`` variable which you can use directly in an
   ## expression. The expression has to return the same type as the sequence you
@@ -428,12 +555,14 @@ template mapIt*(varSeq, op: expr) =
   ##
   ## .. code-block::
   ##   var nums = @[1, 2, 3, 4]
-  ##   nums.mapIt(it * 3)
+  ##   nums.applyIt(it * 3)
   ##   assert nums[0] + nums[3] == 15
-  for i in 0 .. <len(varSeq):
+  for i in 0 .. <varSeq.len:
     let it {.inject.} = varSeq[i]
     varSeq[i] = op
 
+
+
 template newSeqWith*(len: int, init: expr): expr =
   ## creates a new sequence, calling `init` to initialize each value. Example:
   ##
@@ -568,8 +697,8 @@ when isMainModule:
   block: # mapIt tests
     var
       nums = @[1, 2, 3, 4]
-      strings = nums.mapIt(string, $(4 * it))
-    nums.mapIt(it * 3)
+      strings = nums.mapIt($(4 * it))
+    nums.applyIt(it * 3)
     assert nums[0] + nums[3] == 15
 
   block: # distribute tests
@@ -605,15 +734,19 @@ when isMainModule:
     seq2D[0][1] = true
     doAssert seq2D == @[@[true, true], @[true, false], @[false, false], @[false, false]]
 
-  block: # repeat tests
+  block: # cycle tests
     let
       a = @[1, 2, 3]
       b: seq[int] = @[]
 
-    doAssert a.repeat(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
-    doAssert a.repeat(0) == @[]
-    #doAssert a.repeat(-1) == @[] # will not compile!
-    doAssert b.repeat(3) == @[]
+    doAssert a.cycle(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
+    doAssert a.cycle(0) == @[]
+    #doAssert a.cycle(-1) == @[] # will not compile!
+    doAssert b.cycle(3) == @[]
+
+  block: # repeat tests
+    assert repeat(10, 5) == @[10, 10, 10, 10, 10]
+    assert repeat(@[1,2,3], 2) == @[@[1,2,3], @[1,2,3]]
 
   when not defined(testing):
     echo "Finished doc tests"
diff --git a/lib/system.nim b/lib/system.nim
index f7178adcc..89de08c6f 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -2169,53 +2169,6 @@ proc pop*[T](s: var seq[T]): T {.inline, noSideEffect.} =
   result = s[L]
   setLen(s, L)
 
-proc each*[T, S](data: openArray[T], op: proc (x: T): S {.closure.}): seq[S] {.
-  deprecated.} =
-  ## The well-known ``map`` operation from functional programming. Applies
-  ## `op` to every item in `data` and returns the result as a sequence.
-  ##
-  ## **Deprecated since version 0.9:** Use the ``map`` proc instead.
-  newSeq(result, data.len)
-  for i in 0..data.len-1: result[i] = op(data[i])
-
-proc each*[T](data: var openArray[T], op: proc (x: var T) {.closure.}) {.
-  deprecated.} =
-  ## The well-known ``map`` operation from functional programming. Applies
-  ## `op` to every item in `data` modifying it directly.
-  ##
-  ## **Deprecated since version 0.9:** Use the ``map`` proc instead.
-  for i in 0..data.len-1: op(data[i])
-
-proc map*[T, S](data: openArray[T], op: proc (x: T): S {.closure.}): seq[S] =
-  ## Returns a new sequence with the results of `op` applied to every item in
-  ## `data`.
-  ##
-  ## Since the input is not modified you can use this version of ``map`` to
-  ## transform the type of the elements in the input sequence. Example:
-  ##
-  ## .. code-block:: nim
-  ##   let
-  ##     a = @[1, 2, 3, 4]
-  ##     b = map(a, proc(x: int): string = $x)
-  ##   assert b == @["1", "2", "3", "4"]
-  newSeq(result, data.len)
-  for i in 0..data.len-1: result[i] = op(data[i])
-
-proc map*[T](data: var openArray[T], op: proc (x: var T) {.closure.}) =
-  ## Applies `op` to every item in `data` modifying it directly.
-  ##
-  ## Note that this version of ``map`` requires your input and output types to
-  ## be the same, since they are modified in-place. Example:
-  ##
-  ## .. code-block:: nim
-  ##   var a = @["1", "2", "3", "4"]
-  ##   echo repr(a)
-  ##   # --> ["1", "2", "3", "4"]
-  ##   map(a, proc(x: var string) = x &= "42")
-  ##   echo repr(a)
-  ##   # --> ["142", "242", "342", "442"]
-  for i in 0..data.len-1: op(data[i])
-
 iterator fields*[T: tuple|object](x: T): RootObj {.
   magic: "Fields", noSideEffect.}
   ## iterates over every field of `x`. Warning: This really transforms
diff --git a/tests/closure/tclosure4.nim b/tests/closure/tclosure4.nim
index 8e08376b6..10c7cac54 100644
--- a/tests/closure/tclosure4.nim
+++ b/tests/closure/tclosure4.nim
@@ -1,5 +1,5 @@
 
-import json, tables
+import json, tables, sequtils
 
 proc run(json_params: TTable) =
   let json_elems = json_params["files"].elems
diff --git a/tests/collections/tapply.nim b/tests/collections/tapply.nim
new file mode 100644
index 000000000..403321ce1
--- /dev/null
+++ b/tests/collections/tapply.nim
@@ -0,0 +1,7 @@
+import sequtils
+
+var x = @[1, 2, 3]
+x.apply(proc(x: var int) = x = x+10)
+x.apply(proc(x: int): int = x+100)
+x.applyIt(it+5000)
+doAssert x == @[5111, 5112, 5113]
diff --git a/tests/collections/tmapit.nim b/tests/collections/tmapit.nim
new file mode 100644
index 000000000..067561882
--- /dev/null
+++ b/tests/collections/tmapit.nim
@@ -0,0 +1,28 @@
+import sequtils
+
+var x = @[1, 2, 3]
+# This mapIt call will run with preallocation because ``len`` is available.
+var y = x.mapIt($(it+10))
+doAssert y == @["11", "12", "13"]
+
+type structureWithoutLen = object
+  a: array[5, int]
+
+iterator items(s: structureWithoutLen): int {.inline.} =
+  yield s.a[0]
+  yield s.a[1]
+  yield s.a[2]
+  yield s.a[3]
+  yield s.a[4]
+
+var st: structureWithoutLen
+st.a[0] = 0
+st.a[1] = 1
+st.a[2] = 2
+st.a[3] = 3
+st.a[4] = 4
+
+# this will run without preallocating the result
+# since ``len`` is not available
+var r = st.mapIt($(it+10))
+doAssert r == @["10", "11", "12", "13", "14"]
diff --git a/tests/generics/tinferredgenericprocs.nim b/tests/generics/tinferredgenericprocs.nim
index 5cbeabb94..359c71ba8 100644
--- a/tests/generics/tinferredgenericprocs.nim
+++ b/tests/generics/tinferredgenericprocs.nim
@@ -5,6 +5,7 @@ discard """
 3'''
 """
 
+import sequtils
 # https://github.com/Araq/Nim/issues/797
 proc foo[T](s:T):string = $s
 
diff --git a/tests/generics/tmap_auto.nim b/tests/generics/tmap_auto.nim
index dea9b571f..572556722 100644
--- a/tests/generics/tmap_auto.nim
+++ b/tests/generics/tmap_auto.nim
@@ -1,4 +1,4 @@
-import future
+import future, sequtils
 
 let x = map(@[1, 2, 3], x => x+10)
 assert x == @[11, 12, 13]
diff --git a/tests/overload/toverprc.nim b/tests/overload/toverprc.nim
index 78831f744..112eae096 100644
--- a/tests/overload/toverprc.nim
+++ b/tests/overload/toverprc.nim
@@ -5,7 +5,7 @@ yay'''
 
 # Test overloading of procs when used as function pointers
 
-import strutils
+import strutils, sequtils
 
 proc parseInt(x: float): int {.noSideEffect.} = discard
 proc parseInt(x: bool): int {.noSideEffect.} = discard
diff --git a/tests/parser/tcommand_as_expr.nim b/tests/parser/tcommand_as_expr.nim
index 730e9cbb7..a244c8767 100644
--- a/tests/parser/tcommand_as_expr.nim
+++ b/tests/parser/tcommand_as_expr.nim
@@ -5,6 +5,7 @@ discard """
 77'''
 """
 #import math
+import sequtils
 
 proc optarg(x:int, y:int = 0):int = x + 3 * y
 proc singlearg(x:int):int = 20*x
diff --git a/tests/stdlib/tunittest.nim b/tests/stdlib/tunittest.nim
index 4d2a2a340..4b210c23b 100644
--- a/tests/stdlib/tunittest.nim
+++ b/tests/stdlib/tunittest.nim
@@ -1,4 +1,4 @@
-import unittest
+import unittest, sequtils
 
 
 proc doThings(spuds: var int): int =
diff --git a/tests/template/twrongmapit.nim b/tests/template/twrongmapit.nim
index 0a6d694f6..df695fcd6 100644
--- a/tests/template/twrongmapit.nim
+++ b/tests/template/twrongmapit.nim
@@ -27,6 +27,6 @@ when ATTEMPT == 0:
 # bug #1543
 import sequtils
 
-(var i = @[""];i).mapIt(it)
+(var i = @[""];i).applyIt(it)
 # now works:
 echo "##", i[0], "##"
diff --git a/web/news.txt b/web/news.txt
index 2b6079620..45bbe8c44 100644
--- a/web/news.txt
+++ b/web/news.txt
@@ -87,7 +87,13 @@ News
       echo f(0, "abc")
   - The ``ftpclient`` module is now deprecated in favour of the
     ``asyncdispatch`` module.
-
+  - In sequtils.nim renamed ``repeat`` function to ``cycle`` (concatenating
+    a sequence by itself the given times), and also introduced ``repeat``,
+    which repeats an element the given times.
+  - The function ``map`` is moved to sequtils.nim. The inplace ``map`` version
+    is renamed to ``apply``.
+  - The template ``mapIt`` now doesn't require the result's type parameter.
+    Also the inplace ``mapIt`` is renamed to ``apply``.
 
   Library Additions
   -----------------