nim-stint/src/private/conversion.nim

97 lines
2.8 KiB
Nim
Raw Normal View History

# Mpint
# Copyright 2018 Status Research & Development GmbH
# Licensed under either of
#
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
#
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import ./datatypes,
macros, typetraits
2018-04-25 10:52:00 +00:00
func initUintImpl*[InType, OutType](x: InType, _: typedesc[OutType]): OutType {.inline.} =
const
size_in = getSize(x)
size_out = getSize(result)
static:
assert size_out >= size_in, "The result type size (" & $size_out &
" for " & $OutType.name &
") should be equal or bigger than the input type size (" & $size_in &
" for " & $InType.name & ")."
when OutType is SomeUnsignedInt:
result = x.OutType
elif size_in == size_out:
result = cast[type result](x)
else:
2018-04-25 10:52:00 +00:00
result.lo = initUintImpl(x, type result.lo)
func toSubtype*[T: SomeInteger](b: bool, _: typedesc[T]): T {.inline.}=
b.T
2018-04-25 10:52:00 +00:00
func toSubtype*[T: UintImpl](b: bool, _: typedesc[T]): T {.inline.}=
type SubTy = type result.lo
result.lo = toSubtype(b, SubTy)
func zero*[T: BaseUint](_: typedesc[T]): T {.inline.}=
discard
func one*[T: BaseUint](_: typedesc[T]): T {.inline.}=
when T is SomeUnsignedInt:
result = T(1)
else:
let r_ptr = cast[ptr array[getSize(result) div 8, byte]](result.addr)
when system.cpuEndian == bigEndian:
r_ptr[0] = 1
else:
r_ptr[r_ptr[].len - 1] = 1
2018-04-25 10:52:00 +00:00
func toUint*(n: UintImpl): auto {.inline.}=
## Casts a multiprecision integer to an uint of the same size
# TODO: uint128 support
when n.sizeof > 8:
2018-04-25 10:52:00 +00:00
raise newException("Unreachable. You are trying to cast a StUint with more than 64-bit of precision")
elif n.sizeof == 8:
cast[uint64](n)
elif n.sizeof == 4:
cast[uint32](n)
elif n.sizeof == 2:
cast[uint16](n)
else:
2018-04-25 10:52:00 +00:00
raise newException("Unreachable. StUint must be 16-bit minimum and a power of 2")
func toUint*(n: SomeUnsignedInt): SomeUnsignedInt {.inline.}=
## No-op overload of multi-precision int casting
n
func asDoubleUint*(n: BaseUint): auto {.inline.} =
2018-04-25 10:52:00 +00:00
## Convert an integer or StUint to an uint with double the size
type Double = (
when n.sizeof == 4: uint64
elif n.sizeof == 2: uint32
else: uint16
)
n.toUint.Double
2018-04-25 10:52:00 +00:00
func toUintImpl*(n: uint16|uint32|uint64): auto {.inline.} =
## Cast an integer to the corresponding size UintImpl
# Sometimes direct casting doesn't work and we must cast through a pointer
when n is uint64:
2018-04-25 10:52:00 +00:00
return (cast[ptr [UintImpl[uint32]]](unsafeAddr n))[]
elif n is uint32:
2018-04-25 10:52:00 +00:00
return (cast[ptr [UintImpl[uint16]]](unsafeAddr n))[]
elif n is uint16:
2018-04-25 10:52:00 +00:00
return (cast[ptr [UintImpl[uint8]]](unsafeAddr n))[]
2018-04-25 10:52:00 +00:00
func toUintImpl*(n: UintImpl): UintImpl {.inline.} =
## No op
n