summary refs log tree commit diff stats
path: root/lib/pure/bitops.nim
diff options
context:
space:
mode:
authorrockcavera <rockcavera@gmail.com>2021-03-30 07:24:21 -0300
committerGitHub <noreply@github.com>2021-03-30 12:24:21 +0200
commitaf2a7e8cbc3729ac62be64b5683e4a2187160b2f (patch)
tree6d8cbca12a588345b589b30d039e97d6e73b0b99 /lib/pure/bitops.nim
parentf5b1e384a411e1418180ea81bb8fc71bf2feaa26 (diff)
downloadNim-af2a7e8cbc3729ac62be64b5683e4a2187160b2f.tar.gz
Rotation right and left refactored to generics. Continuation of #16622 (#17578)
* Rotation right and left refactored to generics

Continuation of [16622](https://github.com/nim-lang/Nim/pull/16622)

* add runnableExamples
Diffstat (limited to 'lib/pure/bitops.nim')
-rw-r--r--lib/pure/bitops.nim119
1 files changed, 31 insertions, 88 deletions
diff --git a/lib/pure/bitops.nim b/lib/pure/bitops.nim
index 4ef190c1b..b5b08985e 100644
--- a/lib/pure/bitops.nim
+++ b/lib/pure/bitops.nim
@@ -771,7 +771,9 @@ func rotr[T: SomeUnsignedInt](value: T, rot: int32): T {.inline.} =
   let rot = rot and mask
   (value shr rot) or (value shl ((-rot) and mask))
 
-func shiftTypeToImpl(size: static int, shift: int): auto {.inline.} =
+func shiftTypeTo(size: static int, shift: int): auto {.inline.} =
+  ## Returns the `shift` for the rotation according to the compiler and the
+  ## `size`.
   when (defined(vcc) and (size in [4, 8])) or defined(gcc) or defined(icl):
     cint(shift)
   elif (defined(vcc) and (size in [1, 2])) or (defined(clang) and size == 1):
@@ -784,118 +786,59 @@ func shiftTypeToImpl(size: static int, shift: int): auto {.inline.} =
     elif size == 8:
       culonglong(shift)
 
-template shiftTypeTo[T](value: T, shift: int): auto =
-  ## Returns the `shift` for the rotation according to the compiler and the size
-  ## of the` value`.
-  shiftTypeToImpl(sizeof(value), shift)
-
-func rotateLeftBits*(value: uint8, shift: range[0..8]): uint8 {.inline.} =
-  ## Left-rotate bits in a 8-bits value.
+func rotateLeftBits*[T: SomeUnsignedInt](value: T, shift: range[0..(sizeof(T) * 8)]): T {.inline.} =
+  ## Left-rotate bits in a `value`.
   runnableExamples:
     doAssert rotateLeftBits(0b0110_1001'u8, 4) == 0b1001_0110'u8
-
-  when nimvm:
-    rotl(value, shift.int32)
-  else:
-    when useBuiltinsRotate:
-      builtin_rotl8(value.cuchar, shiftTypeTo(value, shift)).uint8
-    else:
-      rotl(value, shift.int32)
-
-func rotateLeftBits*(value: uint16, shift: range[0..16]): uint16 {.inline.} =
-  ## Left-rotate bits in a 16-bits value.
-  runnableExamples:
     doAssert rotateLeftBits(0b00111100_11000011'u16, 8) ==
       0b11000011_00111100'u16
-
-  when nimvm:
-    rotl(value, shift.int32)
-  else:
-    when useBuiltinsRotate:
-      builtin_rotl16(value.cushort, shiftTypeTo(value, shift)).uint16
-    else:
-      rotl(value, shift.int32)
-
-func rotateLeftBits*(value: uint32, shift: range[0..32]): uint32 {.inline.} =
-  ## Left-rotate bits in a 32-bits value.
-  runnableExamples:
     doAssert rotateLeftBits(0b0000111111110000_1111000000001111'u32, 16) ==
       0b1111000000001111_0000111111110000'u32
-
-  when nimvm:
-    rotl(value, shift.int32)
-  else:
-    when useBuiltinsRotate:
-      builtin_rotl32(value.cuint, shiftTypeTo(value, shift)).uint32
-    else:
-      rotl(value, shift.int32)
-
-func rotateLeftBits*(value: uint64, shift: range[0..64]): uint64 {.inline.} =
-  ## Left-rotate bits in a 64-bits value.
-  runnableExamples:
     doAssert rotateLeftBits(0b00000000111111111111111100000000_11111111000000000000000011111111'u64, 32) ==
       0b11111111000000000000000011111111_00000000111111111111111100000000'u64
-
   when nimvm:
     rotl(value, shift.int32)
   else:
-    when useBuiltinsRotate and defined(amd64):
-      builtin_rotl64(value.culonglong, shiftTypeTo(value, shift)).uint64
+    when useBuiltinsRotate:
+      const size = sizeof(T)
+      when size == 1:
+        builtin_rotl8(value.cuchar, shiftTypeTo(size, shift)).T
+      elif size == 2:
+        builtin_rotl16(value.cushort, shiftTypeTo(size, shift)).T
+      elif size == 4:
+        builtin_rotl32(value.cuint, shiftTypeTo(size, shift)).T
+      elif size == 8 and arch64:
+        builtin_rotl64(value.culonglong, shiftTypeTo(size, shift)).T
+      else:
+        rotl(value, shift.int32)
     else:
       rotl(value, shift.int32)
 
-func rotateRightBits*(value: uint8, shift: range[0..8]): uint8 {.inline.} =
-  ## Right-rotate bits in a 8-bits value.
+func rotateRightBits*[T: SomeUnsignedInt](value: T, shift: range[0..(sizeof(T) * 8)]): T {.inline.} =
+  ## Right-rotate bits in a `value`.
   runnableExamples:
     doAssert rotateRightBits(0b0110_1001'u8, 4) == 0b1001_0110'u8
-
-  when nimvm:
-    rotr(value, shift.int32)
-  else:
-    when useBuiltinsRotate:
-      builtin_rotr8(value.cuchar, shiftTypeTo(value, shift)).uint8
-    else:
-      rotr(value, shift.int32)
-
-func rotateRightBits*(value: uint16, shift: range[0..16]): uint16 {.inline.} =
-  ## Right-rotate bits in a 16-bits value.
-  runnableExamples:
     doAssert rotateRightBits(0b00111100_11000011'u16, 8) ==
       0b11000011_00111100'u16
-
-  when nimvm:
-    rotr(value, shift.int32)
-  else:
-    when useBuiltinsRotate:
-      builtin_rotr16(value.cushort, shiftTypeTo(value, shift)).uint16
-    else:
-      rotr(value, shift.int32)
-
-func rotateRightBits*(value: uint32, shift: range[0..32]): uint32 {.inline.} =
-  ## Right-rotate bits in a 32-bits value.
-  runnableExamples:
     doAssert rotateRightBits(0b0000111111110000_1111000000001111'u32, 16) ==
       0b1111000000001111_0000111111110000'u32
-
-  when nimvm:
-    rotr(value, shift.int32)
-  else:
-    when useBuiltinsRotate:
-      builtin_rotr32(value.cuint, shiftTypeTo(value, shift)).uint32
-    else:
-      rotr(value, shift.int32)
-
-func rotateRightBits*(value: uint64, shift: range[0..64]): uint64 {.inline.} =
-  ## Right-rotate bits in a 64-bits value.
-  runnableExamples:
     doAssert rotateRightBits(0b00000000111111111111111100000000_11111111000000000000000011111111'u64, 32) ==
       0b11111111000000000000000011111111_00000000111111111111111100000000'u64
-
   when nimvm:
     rotr(value, shift.int32)
   else:
-    when useBuiltinsRotate and defined(amd64):
-      builtin_rotr64(value.culonglong, shiftTypeTo(value, shift)).uint64
+    when useBuiltinsRotate:
+      const size = sizeof(T)
+      when size == 1:
+        builtin_rotr8(value.cuchar, shiftTypeTo(size, shift)).T
+      elif size == 2:
+        builtin_rotr16(value.cushort, shiftTypeTo(size, shift)).T
+      elif size == 4:
+        builtin_rotr32(value.cuint, shiftTypeTo(size, shift)).T
+      elif size == 8 and arch64:
+        builtin_rotr64(value.culonglong, shiftTypeTo(size, shift)).T
+      else:
+        rotr(value, shift.int32)
     else:
       rotr(value, shift.int32)