summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
authorArne Döring <arne.doering@gmx.net>2017-07-27 18:22:59 +0200
committerArne Döring <arne.doering@gmx.net>2017-07-27 18:22:59 +0200
commit316886542b0a7b9143e0ba96ef93b93a9caadbe6 (patch)
tree4cd490997206250cfdf338ff6e29134a37ad5412 /lib
parent409854c91379610853103cabc3ec29c04fbd13e0 (diff)
downloadNim-316886542b0a7b9143e0ba96ef93b93a9caadbe6.tar.gz
allow a negative distance argument. Improved documentation.
Diffstat (limited to 'lib')
-rw-r--r--lib/pure/algorithm.nim30
1 files changed, 22 insertions, 8 deletions
diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim
index ea7752b18..a808b6703 100644
--- a/lib/pure/algorithm.nim
+++ b/lib/pure/algorithm.nim
@@ -425,7 +425,7 @@ proc rotated_internal[T](arg: openarray[T]; first, middle, last: int): seq[T] =
     result[i] = arg[i]
 
 proc rotateLeft*[T](arg: var openarray[T]; slice: Slice[int]; dist: int): int =
-  ## Performs a left rotation on a range of elements.
+  ## Performs a left rotation on a range of elements. If you want to rotate right, use a negative ``dist``.
   ## Specifically, ``rotate`` rotates the elements at ``slice`` by ``dist`` positions..
   ## The element at index ``slice.a + dist`` will be at index ``slice.a``.
   ## The element at index ``slice.b`` will be at ``slice.a + dist -1``.
@@ -438,28 +438,36 @@ proc rotateLeft*[T](arg: var openarray[T]; slice: Slice[int]; dist: int): int =
   ##   the indices of the element range that should be rotated.
   ##
   ## ``dist``
-  ##   the distance in amount of elements that the data should be rotated.
+  ##   the distance in amount of elements that the data should be rotated. Can be negative, can be any number.
   ##
   ## .. code-block:: nim
   ##     var list     = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
   ##     list.rotateLeft(1 .. 8, 3)
   ##     echo @list  # @[0, 4, 5, 6, 7, 8, 1, 2, 3, 9, 10]
-  arg.rotate_internal(slice.a, slice.a+dist, slice.b + 1)
+  let sliceLen = slice.b + 1 - slice.a
+  let distLeft = ((dist mod sliceLen) + sliceLen) mod sliceLen
+  arg.rotate_internal(slice.a, slice.a+distLeft, slice.b + 1)
 
 proc rotateLeft*[T](arg: var openarray[T]; dist: int): int =
   ## default arguments for slice, so that this procedure operates on the entire
   ## ``arg``, and not just on a part of it.
-  arg.rotate_internal(0, dist, arg.len)
+  let arglen = arg.len
+  let distLeft = ((dist mod arglen) + arglen) mod arglen
+  arg.rotate_internal(0, distLeft, arglen)
 
 proc rotatedLeft*[T](arg: openarray[T]; slice: Slice[int], dist: int): seq[T] =
   ## same as ``rotateLeft``, just with the difference that it does
   ## not modify the argument. It creates a new ``seq`` instead
-  arg.rotated_internal(slice.a, slice.a+dist, slice.b+1)
+  let sliceLen = slice.b + 1 - slice.a
+  let distLeft = ((dist mod sliceLen) + sliceLen) mod sliceLen
+  arg.rotated_internal(slice.a, slice.a+distLeft, slice.b+1)
 
 proc rotatedLeft*[T](arg: openarray[T]; dist: int): seq[T] =
   ## same as ``rotateLeft``, just with the difference that it does
   ## not modify the argument. It creates a new ``seq`` instead
-  arg.rotated_internal(0, dist, arg.len)
+  let arglen = arg.len
+  let distLeft = ((dist mod arglen) + arglen) mod arglen
+  arg.rotated_internal(0, distLeft, arg.len)
 
 when isMainModule:
   var list     = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
@@ -470,11 +478,17 @@ when isMainModule:
   doAssert list  ==  expected
   doAssert list2 == @expected
 
-  var s0,s1,s2 = "xxxabcdefgxxx"
+  var s0,s1,s2,s3,s4,s5 = "xxxabcdefgxxx"
 
   doAssert s0.rotateLeft(3 ..< 10, 3) == 7
   doAssert s0 == "xxxdefgabcxxx"
   doAssert s1.rotateLeft(3 ..< 10, 2) == 8
   doAssert s1 == "xxxcdefgabxxx"
   doAssert s2.rotateLeft(3 ..< 10, 4) == 6
-  doassert s2 == "xxxefgabcdxxx"
+  doAssert s2 == "xxxefgabcdxxx"
+  doAssert s3.rotateLeft(3 ..< 10, -3) == 6
+  doAssert s3 == "xxxefgabcdxxx"
+  doAssert s4.rotateLeft(3 ..< 10, -10) == 6
+  doAssert s4 == "xxxefgabcdxxx"
+  doAssert s5.rotateLeft(3 ..< 10, 11) == 6
+  doAssert s5 == "xxxefgabcdxxx"