## This module is for compiler internal use only. For reliable error ## messages and range checks, the compiler needs a data type that can ## hold all from ``low(BiggestInt)`` to ``high(BiggestUInt)``, This ## type is for that purpose. from math import trunc type Int128* = object udata: array[4,uint32] template sdata(arg: Int128, idx: int): int32 = # udata and sdata was supposed to be in a union, but unions are # handled incorrectly in the VM. cast[ptr int32](arg.udata[idx].unsafeAddr)[] # encoding least significant int first (like LittleEndian) const Zero* = Int128(udata: [0'u32,0,0,0]) One* = Int128(udata: [1'u32,0,0,0]) Ten* = Int128(udata: [10'u32,0,0,0]) Min = Int128(udata: [0'u32,0,0,0x80000000'u32]) Max = Int128(udata: [high(uint32),high(uint32),high(uint32),uint32(high(int32))]) NegOne* = Int128(udata: [0xffffffff'u32,0xffffffff'u32,0xffffffff'u32,0xffffffff'u32]) template low*(t: typedesc[Int128]): Int128 = Min template high*(t: typedesc[Int128]): Int128 = Max proc `$`*(a: Int128): string proc toInt128*[T: SomeInteger](arg: T): Int128 = when T is SomeUnsignedInt: when sizeof(arg) <= 4: result.udata[0] = uint32(arg) else: result.udata[0] = uint32(arg and T(0xffffffff)) result.udata[1] = uint32(arg shr 32) else: when sizeof(arg) <= 4: result.sdata(0) = int32(arg) if arg < 0: # sign extend result.sdata(1) = -1 result.sdata(2) = -1 result.sdata(3) = -1 else: let tmp = int64(arg) result.udata[0] = uint32(tmp and 0xffffffff) result.sdata(1) = int32(tmp shr 32) if arg < 0: # sign extend result.sdata(2) = -1 result.sdata(3) = -1 template isNegative(arg: Int128): bool = arg.sdata(3) < 0 template isNegative(arg: int32): bool = arg < 0 proc bitconcat(a,b: uint32): uint64 = (uint64(a) shl 32) or uint64(b) proc bitsplit(a: uint64): (uint32,uint32) = (cast[uint32](a shr 32), cast[uint32](a)) proc toInt64*(arg: Int128): int64 = if isNegative(arg): assert(arg.sdata(3) == -1, "out of range") assert(arg.sdata(2) == -1, "out of range") else: assert(arg.sdata(3) == 0, "out of range") assert(arg.sdata(2) == 0, "out of range") cast[int64](bitconcat(arg.udata[1], arg.udata[0])) proc toInt64Checked*(arg: Int128; onError: int64): int64 = if isNegative(arg): if arg.sdata(3) != -1 or arg.sdata(2) != -1: return onError else: if arg.sdata(3) != 0 or arg.sdata(2) != 0: return onError return cast[int64](bitconcat(arg.udata[1], arg.udata[0])) proc toInt32*(arg: Int128): int32 = if isNegative(arg): assert(arg.sdata(3) == -1, "out of range") assert(arg.sdata(2) == -1, "out of range") assert(arg.sdata(1) == -1, "out of range") else: assert(arg.sdata(3) == 0, "out of range") assert(arg.sdata(2) == 0, "out of range") assert(arg.sdata(1) == 0, "out of range") arg.sdata(0) proc toInt16*(arg: Int128): int16 = if isNegative(arg): assert(arg.sdata(3) == -1, "out of range") assert(arg.sdata(2) == -1, "out of range") assert(arg.sdata(1) == -1, "out of range") else: assert(arg.sdata(3) == 0, "out of range") assert(arg.sdata(2) == 0, "out of range") assert(arg.sdata(1) == 0, "out of range") int16(arg.sdata(0)) proc toInt8*(arg: Int128): int8 = if isNegative(arg): assert(arg.sdata(3) == -1, "out of range") assert(arg.sdata(2) == -1, "out of range") assert(arg.sdata(1) == -1, "out of range") else: assert(arg.sdata(3) == 0, "out of range") assert(arg.sdata(2) == 0, "out of range") assert(arg.sdata(1) == 0, "out of range") int8(arg.sdata(0)) proc toInt*(arg:
type
Comparable = concept a
(a < a) is bool
proc myMax(a, b: Comparable): Comparable =
if a < b:
return b
else:
return a
doAssert myMax(5, 10) == 10
doAssert myMax(31.3, 1.23124) == 31.3