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
This commit is contained in:
rockcavera
2021-03-30 07:24:21 -03:00
committed by GitHub
parent f5b1e384a4
commit af2a7e8cbc

View File

@@ -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
doAssert rotateRightBits(0b00000000111111111111111100000000_11111111000000000000000011111111'u64, 32) ==
0b11111111000000000000000011111111_00000000111111111111111100000000'u64
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
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)