typetraits: add toSigned, toUnsigned (#18445)
* typetraits: add toSigned, toUnsigned * improve and add tests Co-authored-by: Andreas Rumpf <rumpf_a@web.de> Co-authored-by: flywind <xzsflywind@gmail.com>
This commit is contained in:
parent
1807de38e5
commit
e78ef57c93
7 changed files with 85 additions and 33 deletions
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
import macros
|
||||
import std/private/since
|
||||
from std/private/bitops_utils import forwardImpl, toUnsigned
|
||||
from std/private/bitops_utils import forwardImpl, castToUnsigned
|
||||
|
||||
func bitnot*[T: SomeInteger](x: T): T {.magic: "BitnotI".}
|
||||
## Computes the `bitwise complement` of the integer `x`.
|
||||
|
|
@ -72,7 +72,7 @@ func bitsliced*[T: SomeInteger](v: T; slice: Slice[int]): T {.inline, since: (1,
|
|||
|
||||
let
|
||||
upmost = sizeof(T) * 8 - 1
|
||||
uv = when v is SomeUnsignedInt: v else: v.toUnsigned
|
||||
uv = v.castToUnsigned
|
||||
(uv shl (upmost - slice.b) shr (upmost - slice.b + slice.a)).T
|
||||
|
||||
proc bitslice*[T: SomeInteger](v: var T; slice: Slice[int]) {.inline, since: (1, 3).} =
|
||||
|
|
@ -84,7 +84,7 @@ proc bitslice*[T: SomeInteger](v: var T; slice: Slice[int]) {.inline, since: (1,
|
|||
|
||||
let
|
||||
upmost = sizeof(T) * 8 - 1
|
||||
uv = when v is SomeUnsignedInt: v else: v.toUnsigned
|
||||
uv = v.castToUnsigned
|
||||
v = (uv shl (upmost - slice.b) shr (upmost - slice.b + slice.a)).T
|
||||
|
||||
func toMask*[T: SomeInteger](slice: Slice[int]): T {.inline, since: (1, 3).} =
|
||||
|
|
@ -95,10 +95,7 @@ func toMask*[T: SomeInteger](slice: Slice[int]): T {.inline, since: (1, 3).} =
|
|||
|
||||
let
|
||||
upmost = sizeof(T) * 8 - 1
|
||||
bitmask = when T is SomeUnsignedInt:
|
||||
bitnot(0.T)
|
||||
else:
|
||||
bitnot(0.T).toUnsigned
|
||||
bitmask = bitnot(0.T).castToUnsigned
|
||||
(bitmask shl (upmost - slice.b + slice.a) shr (upmost - slice.b)).T
|
||||
|
||||
proc masked*[T: SomeInteger](v, mask :T): T {.inline, since: (1, 3).} =
|
||||
|
|
@ -505,8 +502,7 @@ func parityBits*(x: SomeInteger): int {.inline.} =
|
|||
|
||||
# Can be used a base if creating ASM version.
|
||||
# https://stackoverflow.com/questions/21617970/how-to-check-if-value-has-even-parity-of-bits-or-odd
|
||||
when x is SomeSignedInt:
|
||||
let x = x.toUnsigned
|
||||
let x = x.castToUnsigned
|
||||
when nimvm:
|
||||
result = forwardImpl(parityImpl, x)
|
||||
else:
|
||||
|
|
@ -529,8 +525,7 @@ func firstSetBit*(x: SomeInteger): int {.inline.} =
|
|||
doAssert firstSetBit(0b0000_1111'u8) == 1
|
||||
|
||||
# GCC builtin 'builtin_ffs' already handle zero input.
|
||||
when x is SomeSignedInt:
|
||||
let x = x.toUnsigned
|
||||
let x = x.castToUnsigned
|
||||
when nimvm:
|
||||
when noUndefined:
|
||||
if x == 0:
|
||||
|
|
@ -572,8 +567,7 @@ func fastLog2*(x: SomeInteger): int {.inline.} =
|
|||
doAssert fastLog2(0b0000_1000'u8) == 3
|
||||
doAssert fastLog2(0b0000_1111'u8) == 3
|
||||
|
||||
when x is SomeSignedInt:
|
||||
let x = x.toUnsigned
|
||||
let x = x.castToUnsigned
|
||||
when noUndefined:
|
||||
if x == 0:
|
||||
return -1
|
||||
|
|
@ -615,8 +609,7 @@ func countLeadingZeroBits*(x: SomeInteger): int {.inline.} =
|
|||
doAssert countLeadingZeroBits(0b0000_1000'u8) == 4
|
||||
doAssert countLeadingZeroBits(0b0000_1111'u8) == 4
|
||||
|
||||
when x is SomeSignedInt:
|
||||
let x = x.toUnsigned
|
||||
let x = x.castToUnsigned
|
||||
when noUndefined:
|
||||
if x == 0:
|
||||
return 0
|
||||
|
|
@ -644,8 +637,7 @@ func countTrailingZeroBits*(x: SomeInteger): int {.inline.} =
|
|||
doAssert countTrailingZeroBits(0b0000_1000'u8) == 3
|
||||
doAssert countTrailingZeroBits(0b0000_1111'u8) == 0
|
||||
|
||||
when x is SomeSignedInt:
|
||||
let x = x.toUnsigned
|
||||
let x = x.castToUnsigned
|
||||
when noUndefined:
|
||||
if x == 0:
|
||||
return 0
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ runnableExamples:
|
|||
assert C[float] is HoleyEnum
|
||||
|
||||
proc name*(t: typedesc): string {.magic: "TypeTrait".} =
|
||||
## Returns the name of the given type.
|
||||
## Returns the name of `t`.
|
||||
##
|
||||
## Alias for `system.\`$\`(t) <dollars.html#$,typedesc>`_ since Nim v0.20.
|
||||
runnableExamples:
|
||||
|
|
@ -43,7 +43,7 @@ proc name*(t: typedesc): string {.magic: "TypeTrait".} =
|
|||
doAssert name(seq[string]) == "seq[string]"
|
||||
|
||||
proc arity*(t: typedesc): int {.magic: "TypeTrait".} =
|
||||
## Returns the arity of the given type. This is the number of "type"
|
||||
## Returns the arity of `t`. This is the number of "type"
|
||||
## components or the number of generic parameters a given type `t` has.
|
||||
runnableExamples:
|
||||
doAssert arity(int) == 0
|
||||
|
|
@ -92,8 +92,7 @@ proc stripGenericParams*(t: typedesc): typedesc {.magic: "TypeTrait".} =
|
|||
doAssert stripGenericParams(int) is int
|
||||
|
||||
proc supportsCopyMem*(t: typedesc): bool {.magic: "TypeTrait".}
|
||||
## This trait returns true if the type `t` is safe to use for
|
||||
## `copyMem`:idx:.
|
||||
## Returns true if `t` is safe to use for `copyMem`:idx:.
|
||||
##
|
||||
## Other languages name a type like these `blob`:idx:.
|
||||
|
||||
|
|
@ -289,9 +288,38 @@ since (1, 1):
|
|||
proc hasClosureImpl(n: NimNode): bool = discard "see compiler/vmops.nim"
|
||||
|
||||
proc hasClosure*(fn: NimNode): bool {.since: (1, 5, 1).} =
|
||||
## Return true if the func/proc/etc `fn` has `closure`.
|
||||
## Returns true if the func/proc/etc `fn` has `closure`.
|
||||
## `fn` has to be a resolved symbol of kind `nnkSym`. This
|
||||
## implies that the macro that calls this proc should accept `typed`
|
||||
## arguments and not `untyped` arguments.
|
||||
expectKind fn, nnkSym
|
||||
result = hasClosureImpl(fn)
|
||||
|
||||
template toUnsigned*(T: typedesc[SomeInteger and not range]): untyped =
|
||||
## Returns an unsigned type with same bit size as `T`.
|
||||
runnableExamples:
|
||||
assert int8.toUnsigned is uint8
|
||||
assert uint.toUnsigned is uint
|
||||
assert int.toUnsigned is uint
|
||||
# range types are currently unsupported:
|
||||
assert not compiles(toUnsigned(range[0..7]))
|
||||
when T is int8: uint8
|
||||
elif T is int16: uint16
|
||||
elif T is int32: uint32
|
||||
elif T is int64: uint64
|
||||
elif T is int: uint
|
||||
else: T
|
||||
|
||||
template toSigned*(T: typedesc[SomeInteger and not range]): untyped =
|
||||
## Returns a signed type with same bit size as `T`.
|
||||
runnableExamples:
|
||||
assert int8.toSigned is int8
|
||||
assert uint16.toSigned is int16
|
||||
# range types are currently unsupported:
|
||||
assert not compiles(toSigned(range[0..7]))
|
||||
when T is uint8: int8
|
||||
elif T is uint16: int16
|
||||
elif T is uint32: int32
|
||||
elif T is uint64: int64
|
||||
elif T is uint: int
|
||||
else: T
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue