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
commit af2a7e8cbc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -771,7 +771,9 @@ func rotr[T: SomeUnsignedInt](value: T, rot: int32): T {.inline.} =
let rot = rot and mask let rot = rot and mask
(value shr rot) or (value shl ((-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): when (defined(vcc) and (size in [4, 8])) or defined(gcc) or defined(icl):
cint(shift) cint(shift)
elif (defined(vcc) and (size in [1, 2])) or (defined(clang) and size == 1): 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: elif size == 8:
culonglong(shift) culonglong(shift)
template shiftTypeTo[T](value: T, shift: int): auto = func rotateLeftBits*[T: SomeUnsignedInt](value: T, shift: range[0..(sizeof(T) * 8)]): T {.inline.} =
## Returns the `shift` for the rotation according to the compiler and the size ## Left-rotate bits in a `value`.
## 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.
runnableExamples: runnableExamples:
doAssert rotateLeftBits(0b0110_1001'u8, 4) == 0b1001_0110'u8 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) == doAssert rotateLeftBits(0b00111100_11000011'u16, 8) ==
0b11000011_00111100'u16 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) == doAssert rotateLeftBits(0b0000111111110000_1111000000001111'u32, 16) ==
0b1111000000001111_0000111111110000'u32 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) == doAssert rotateLeftBits(0b00000000111111111111111100000000_11111111000000000000000011111111'u64, 32) ==
0b11111111000000000000000011111111_00000000111111111111111100000000'u64 0b11111111000000000000000011111111_00000000111111111111111100000000'u64
when nimvm: when nimvm:
rotl(value, shift.int32) rotl(value, shift.int32)
else: else:
when useBuiltinsRotate and defined(amd64): when useBuiltinsRotate:
builtin_rotl64(value.culonglong, shiftTypeTo(value, shift)).uint64 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: else:
rotl(value, shift.int32) rotl(value, shift.int32)
func rotateRightBits*(value: uint8, shift: range[0..8]): uint8 {.inline.} = func rotateRightBits*[T: SomeUnsignedInt](value: T, shift: range[0..(sizeof(T) * 8)]): T {.inline.} =
## Right-rotate bits in a 8-bits value. ## Right-rotate bits in a `value`.
runnableExamples: runnableExamples:
doAssert rotateRightBits(0b0110_1001'u8, 4) == 0b1001_0110'u8 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) == doAssert rotateRightBits(0b00111100_11000011'u16, 8) ==
0b11000011_00111100'u16 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) == doAssert rotateRightBits(0b0000111111110000_1111000000001111'u32, 16) ==
0b1111000000001111_0000111111110000'u32 0b1111000000001111_0000111111110000'u32
doAssert rotateRightBits(0b00000000111111111111111100000000_11111111000000000000000011111111'u64, 32) ==
0b11111111000000000000000011111111_00000000111111111111111100000000'u64
when nimvm: when nimvm:
rotr(value, shift.int32) rotr(value, shift.int32)
else: else:
when useBuiltinsRotate: when useBuiltinsRotate:
builtin_rotr32(value.cuint, shiftTypeTo(value, shift)).uint32 const size = sizeof(T)
else: when size == 1:
rotr(value, shift.int32) builtin_rotr8(value.cuchar, shiftTypeTo(size, shift)).T
elif size == 2:
func rotateRightBits*(value: uint64, shift: range[0..64]): uint64 {.inline.} = builtin_rotr16(value.cushort, shiftTypeTo(size, shift)).T
## Right-rotate bits in a 64-bits value. elif size == 4:
runnableExamples: builtin_rotr32(value.cuint, shiftTypeTo(size, shift)).T
doAssert rotateRightBits(0b00000000111111111111111100000000_11111111000000000000000011111111'u64, 32) == elif size == 8 and arch64:
0b11111111000000000000000011111111_00000000111111111111111100000000'u64 builtin_rotr64(value.culonglong, shiftTypeTo(size, shift)).T
else:
when nimvm: rotr(value, shift.int32)
rotr(value, shift.int32)
else:
when useBuiltinsRotate and defined(amd64):
builtin_rotr64(value.culonglong, shiftTypeTo(value, shift)).uint64
else: else:
rotr(value, shift.int32) rotr(value, shift.int32)