int128.nim 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. ## This module is for compiler internal use only. For reliable error
  2. ## messages and range checks, the compiler needs a data type that can
  3. ## hold all from `low(BiggestInt)` to `high(BiggestUInt)`, This
  4. ## type is for that purpose.
  5. from math import trunc
  6. type
  7. Int128* = object
  8. udata: array[4, uint32]
  9. template sdata(arg: Int128, idx: int): int32 =
  10. # udata and sdata was supposed to be in a union, but unions are
  11. # handled incorrectly in the VM.
  12. cast[ptr int32](arg.udata[idx].unsafeAddr)[]
  13. # encoding least significant int first (like LittleEndian)
  14. const
  15. Zero* = Int128(udata: [0'u32, 0, 0, 0])
  16. One* = Int128(udata: [1'u32, 0, 0, 0])
  17. Ten* = Int128(udata: [10'u32, 0, 0, 0])
  18. Min = Int128(udata: [0'u32, 0, 0, 0x80000000'u32])
  19. Max = Int128(udata: [high(uint32), high(uint32), high(uint32), uint32(high(int32))])
  20. NegOne* = Int128(udata: [0xffffffff'u32, 0xffffffff'u32, 0xffffffff'u32, 0xffffffff'u32])
  21. template low*(t: typedesc[Int128]): Int128 = Min
  22. template high*(t: typedesc[Int128]): Int128 = Max
  23. proc `$`*(a: Int128): string
  24. proc toInt128*[T: SomeInteger | bool](arg: T): Int128 =
  25. when T is bool: result.sdata(0) = int32(arg)
  26. elif T is SomeUnsignedInt:
  27. when sizeof(arg) <= 4:
  28. result.udata[0] = uint32(arg)
  29. else:
  30. result.udata[0] = uint32(arg and T(0xffffffff))
  31. result.udata[1] = uint32(arg shr 32)
  32. elif sizeof(arg) <= 4:
  33. result.sdata(0) = int32(arg)
  34. if arg < 0: # sign extend
  35. result.sdata(1) = -1
  36. result.sdata(2) = -1
  37. result.sdata(3) = -1
  38. else:
  39. let tmp = int64(arg)
  40. result.udata[0] = uint32(tmp and 0xffffffff)
  41. result.sdata(1) = int32(tmp shr 32)
  42. if arg < 0: # sign extend
  43. result.sdata(2) = -1
  44. result.sdata(3) = -1
  45. template isNegative(arg: Int128): bool =
  46. arg.sdata(3) < 0
  47. template isNegative(arg: int32): bool =
  48. arg < 0
  49. proc bitconcat(a, b: uint32): uint64 =
  50. (uint64(a) shl 32) or uint64(b)
  51. proc bitsplit(a: uint64): (uint32, uint32) =
  52. (cast[uint32](a shr 32), cast[uint32](a))
  53. proc toInt64*(arg: Int128): int64 =
  54. if isNegative(arg):
  55. assert(arg.sdata(3) == -1, "out of range")
  56. assert(arg.sdata(2) == -1, "out of range")
  57. else:
  58. assert(arg.sdata(3) == 0, "out of range")
  59. assert(arg.sdata(2) == 0, "out of range")
  60. cast[int64](bitconcat(arg.udata[1], arg.udata[0]))
  61. proc toInt64Checked*(arg: Int128; onError: int64): int64 =
  62. if isNegative(arg):
  63. if arg.sdata(3) != -1 or arg.sdata(2) != -1:
  64. return onError
  65. else:
  66. if arg.sdata(3) != 0 or arg.sdata(2) != 0:
  67. return onError
  68. return cast[int64](bitconcat(arg.udata[1], arg.udata[0]))
  69. proc toInt32*(arg: Int128): int32 =
  70. if isNegative(arg):
  71. assert(arg.sdata(3) == -1, "out of range")
  72. assert(arg.sdata(2) == -1, "out of range")
  73. assert(arg.sdata(1) == -1, "out of range")
  74. else:
  75. assert(arg.sdata(3) == 0, "out of range")
  76. assert(arg.sdata(2) == 0, "out of range")
  77. assert(arg.sdata(1) == 0, "out of range")
  78. arg.sdata(0)
  79. proc toInt16*(arg: Int128): int16 =
  80. if isNegative(arg):
  81. assert(arg.sdata(3) == -1, "out of range")
  82. assert(arg.sdata(2) == -1, "out of range")
  83. assert(arg.sdata(1) == -1, "out of range")
  84. else:
  85. assert(arg.sdata(3) == 0, "out of range")
  86. assert(arg.sdata(2) == 0, "out of range")
  87. assert(arg.sdata(1) == 0, "out of range")
  88. int16(arg.sdata(0))
  89. proc toInt8*(arg: Int128): int8 =
  90. if isNegative(arg):
  91. assert(arg.sdata(3) == -1, "out of range")
  92. assert(arg.sdata(2) == -1, "out of range")
  93. assert(arg.sdata(1) == -1, "out of range")
  94. else:
  95. assert(arg.sdata(3) == 0, "out of range")
  96. assert(arg.sdata(2) == 0, "out of range")
  97. assert(arg.sdata(1) == 0, "out of range")
  98. int8(arg.sdata(0))
  99. proc toInt*(arg: Int128): int =
  100. when sizeof(int) == 4:
  101. cast[int](toInt32(arg))
  102. else:
  103. cast[int](toInt64(arg))
  104. proc toUInt64*(arg: Int128): uint64 =
  105. assert(arg.udata[3] == 0)
  106. assert(arg.udata[2] == 0)
  107. bitconcat(arg.udata[1], arg.udata[0])
  108. proc toUInt32*(arg: Int128): uint32 =
  109. assert(arg.udata[3] == 0)
  110. assert(arg.udata[2] == 0)
  111. assert(arg.udata[1] == 0)
  112. arg.udata[0]
  113. proc toUInt16*(arg: Int128): uint16 =
  114. assert(arg.udata[3] == 0)
  115. assert(arg.udata[2] == 0)
  116. assert(arg.udata[1] == 0)
  117. uint16(arg.udata[0])
  118. proc toUInt8*(arg: Int128): uint8 =
  119. assert(arg.udata[3] == 0)
  120. assert(arg.udata[2] == 0)
  121. assert(arg.udata[1] == 0)
  122. uint8(arg.udata[0])
  123. proc toUInt*(arg: Int128): uint =
  124. when sizeof(int) == 4:
  125. cast[uint](toInt32(arg))
  126. else:
  127. cast[uint](toInt64(arg))
  128. proc castToInt64*(arg: Int128): int64 =
  129. ## Conversion to int64 without range check.
  130. cast[int64](bitconcat(arg.udata[1], arg.udata[0]))
  131. proc castToUInt64*(arg: Int128): uint64 =
  132. ## Conversion to uint64 without range check.
  133. cast[uint64](bitconcat(arg.udata[1], arg.udata[0]))
  134. proc addToHex(result: var string; arg: uint32) =
  135. for i in 0..<8:
  136. let idx = (arg shr ((7-i) * 4)) and 0xf
  137. result.add "0123456789abcdef"[idx]
  138. proc addToHex*(result: var string; arg: Int128) =
  139. var i = 3
  140. while i >= 0:
  141. result.addToHex(arg.udata[i])
  142. i -= 1
  143. proc toHex*(arg: Int128): string =
  144. result.addToHex(arg)
  145. proc inc*(a: var Int128, y: uint32 = 1) =
  146. a.udata[0] += y
  147. if unlikely(a.udata[0] < y):
  148. a.udata[1].inc
  149. if unlikely(a.udata[1] == 0):
  150. a.udata[2].inc
  151. if unlikely(a.udata[2] == 0):
  152. a.udata[3].inc
  153. doAssert(a.sdata(3) != low(int32), "overflow")
  154. proc cmp*(a, b: Int128): int =
  155. let tmp1 = cmp(a.sdata(3), b.sdata(3))
  156. if tmp1 != 0: return tmp1
  157. let tmp2 = cmp(a.udata[2], b.udata[2])
  158. if tmp2 != 0: return tmp2
  159. let tmp3 = cmp(a.udata[1], b.udata[1])
  160. if tmp3 != 0: return tmp3
  161. let tmp4 = cmp(a.udata[0], b.udata[0])
  162. return tmp4
  163. proc `<`*(a, b: Int128): bool =
  164. cmp(a, b) < 0
  165. proc `<=`*(a, b: Int128): bool =
  166. cmp(a, b) <= 0
  167. proc `==`*(a, b: Int128): bool =
  168. if a.udata[0] != b.udata[0]: return false
  169. if a.udata[1] != b.udata[1]: return false
  170. if a.udata[2] != b.udata[2]: return false
  171. if a.udata[3] != b.udata[3]: return false
  172. return true
  173. proc inplaceBitnot(a: var Int128) =
  174. a.udata[0] = not a.udata[0]
  175. a.udata[1] = not a.udata[1]
  176. a.udata[2] = not a.udata[2]
  177. a.udata[3] = not a.udata[3]
  178. proc bitnot*(a: Int128): Int128 =
  179. result.udata[0] = not a.udata[0]
  180. result.udata[1] = not a.udata[1]
  181. result.udata[2] = not a.udata[2]
  182. result.udata[3] = not a.udata[3]
  183. proc bitand*(a, b: Int128): Int128 =
  184. result.udata[0] = a.udata[0] and b.udata[0]
  185. result.udata[1] = a.udata[1] and b.udata[1]
  186. result.udata[2] = a.udata[2] and b.udata[2]
  187. result.udata[3] = a.udata[3] and b.udata[3]
  188. proc bitor*(a, b: Int128): Int128 =
  189. result.udata[0] = a.udata[0] or b.udata[0]
  190. result.udata[1] = a.udata[1] or b.udata[1]
  191. result.udata[2] = a.udata[2] or b.udata[2]
  192. result.udata[3] = a.udata[3] or b.udata[3]
  193. proc bitxor*(a, b: Int128): Int128 =
  194. result.udata[0] = a.udata[0] xor b.udata[0]
  195. result.udata[1] = a.udata[1] xor b.udata[1]
  196. result.udata[2] = a.udata[2] xor b.udata[2]
  197. result.udata[3] = a.udata[3] xor b.udata[3]
  198. proc `shr`*(a: Int128, b: int): Int128 =
  199. let b = b and 127
  200. if b < 32:
  201. result.sdata(3) = a.sdata(3) shr b
  202. result.udata[2] = cast[uint32](bitconcat(a.udata[3], a.udata[2]) shr b)
  203. result.udata[1] = cast[uint32](bitconcat(a.udata[2], a.udata[1]) shr b)
  204. result.udata[0] = cast[uint32](bitconcat(a.udata[1], a.udata[0]) shr b)
  205. elif b < 64:
  206. if isNegative(a):
  207. result.sdata(3) = -1
  208. result.sdata(2) = a.sdata(3) shr (b and 31)
  209. result.udata[1] = cast[uint32](bitconcat(a.udata[3], a.udata[2]) shr (b and 31))
  210. result.udata[0] = cast[uint32](bitconcat(a.udata[2], a.udata[1]) shr (b and 31))
  211. elif b < 96:
  212. if isNegative(a):
  213. result.sdata(3) = -1
  214. result.sdata(2) = -1
  215. result.sdata(1) = a.sdata(3) shr (b and 31)
  216. result.udata[0] = cast[uint32](bitconcat(a.udata[3], a.udata[2]) shr (b and 31))
  217. else: # b < 128
  218. if isNegative(a):
  219. result.sdata(3) = -1
  220. result.sdata(2) = -1
  221. result.sdata(1) = -1
  222. result.sdata(0) = a.sdata(3) shr (b and 31)
  223. proc `shl`*(a: Int128, b: int): Int128 =
  224. let b = b and 127
  225. if b < 32:
  226. result.udata[0] = a.udata[0] shl b
  227. result.udata[1] = cast[uint32]((bitconcat(a.udata[1], a.udata[0]) shl b) shr 32)
  228. result.udata[2] = cast[uint32]((bitconcat(a.udata[2], a.udata[1]) shl b) shr 32)
  229. result.udata[3] = cast[uint32]((bitconcat(a.udata[3], a.udata[2]) shl b) shr 32)
  230. elif b < 64:
  231. result.udata[0] = 0
  232. result.udata[1] = a.udata[0] shl (b and 31)
  233. result.udata[2] = cast[uint32]((bitconcat(a.udata[1], a.udata[0]) shl (b and 31)) shr 32)
  234. result.udata[3] = cast[uint32]((bitconcat(a.udata[2], a.udata[1]) shl (b and 31)) shr 32)
  235. elif b < 96:
  236. result.udata[0] = 0
  237. result.udata[1] = 0
  238. result.udata[2] = a.udata[0] shl (b and 31)
  239. result.udata[3] = cast[uint32]((bitconcat(a.udata[1], a.udata[0]) shl (b and 31)) shr 32)
  240. else:
  241. result.udata[0] = 0
  242. result.udata[1] = 0
  243. result.udata[2] = 0
  244. result.udata[3] = a.udata[0] shl (b and 31)
  245. proc `+`*(a, b: Int128): Int128 =
  246. let tmp0 = uint64(a.udata[0]) + uint64(b.udata[0])
  247. result.udata[0] = cast[uint32](tmp0)
  248. let tmp1 = uint64(a.udata[1]) + uint64(b.udata[1]) + (tmp0 shr 32)
  249. result.udata[1] = cast[uint32](tmp1)
  250. let tmp2 = uint64(a.udata[2]) + uint64(b.udata[2]) + (tmp1 shr 32)
  251. result.udata[2] = cast[uint32](tmp2)
  252. let tmp3 = uint64(a.udata[3]) + uint64(b.udata[3]) + (tmp2 shr 32)
  253. result.udata[3] = cast[uint32](tmp3)
  254. proc `+=`*(a: var Int128, b: Int128) =
  255. a = a + b
  256. proc `-`*(a: Int128): Int128 =
  257. result = bitnot(a)
  258. result.inc
  259. proc `-`*(a, b: Int128): Int128 =
  260. a + (-b)
  261. proc `-=`*(a: var Int128, b: Int128) =
  262. a = a - b
  263. proc abs*(a: Int128): Int128 =
  264. if isNegative(a):
  265. -a
  266. else:
  267. a
  268. proc abs(a: int32): int =
  269. if a < 0: -a else: a
  270. proc `*`(a: Int128, b: uint32): Int128 =
  271. let tmp0 = uint64(a.udata[0]) * uint64(b)
  272. let tmp1 = uint64(a.udata[1]) * uint64(b)
  273. let tmp2 = uint64(a.udata[2]) * uint64(b)
  274. let tmp3 = uint64(a.udata[3]) * uint64(b)
  275. if unlikely(tmp3 > uint64(high(int32))):
  276. assert(false, "overflow")
  277. result.udata[0] = cast[uint32](tmp0)
  278. result.udata[1] = cast[uint32](tmp1) + cast[uint32](tmp0 shr 32)
  279. result.udata[2] = cast[uint32](tmp2) + cast[uint32](tmp1 shr 32)
  280. result.udata[3] = cast[uint32](tmp3) + cast[uint32](tmp2 shr 32)
  281. proc `*`*(a: Int128, b: int32): Int128 =
  282. result = a * cast[uint32](abs(b))
  283. if b < 0:
  284. result = -result
  285. proc `*=`*(a: var Int128, b: int32): Int128 =
  286. result = result * b
  287. proc makeInt128(high, low: uint64): Int128 =
  288. result.udata[0] = cast[uint32](low)
  289. result.udata[1] = cast[uint32](low shr 32)
  290. result.udata[2] = cast[uint32](high)
  291. result.udata[3] = cast[uint32](high shr 32)
  292. proc high64(a: Int128): uint64 =
  293. bitconcat(a.udata[3], a.udata[2])
  294. proc low64(a: Int128): uint64 =
  295. bitconcat(a.udata[1], a.udata[0])
  296. proc `*`*(lhs, rhs: Int128): Int128 =
  297. let
  298. a = cast[uint64](lhs.udata[0])
  299. b = cast[uint64](lhs.udata[1])
  300. c = cast[uint64](lhs.udata[2])
  301. d = cast[uint64](lhs.udata[3])
  302. e = cast[uint64](rhs.udata[0])
  303. f = cast[uint64](rhs.udata[1])
  304. g = cast[uint64](rhs.udata[2])
  305. h = cast[uint64](rhs.udata[3])
  306. let a32 = cast[uint64](lhs.udata[1])
  307. let a00 = cast[uint64](lhs.udata[0])
  308. let b32 = cast[uint64](rhs.udata[1])
  309. let b00 = cast[uint64](rhs.udata[0])
  310. result = makeInt128(high64(lhs) * low64(rhs) + low64(lhs) * high64(rhs) + a32 * b32, a00 * b00)
  311. result += toInt128(a32 * b00) shl 32
  312. result += toInt128(a00 * b32) shl 32
  313. proc `*=`*(a: var Int128, b: Int128) =
  314. a = a * b
  315. import bitops
  316. proc fastLog2*(a: Int128): int =
  317. if a.udata[3] != 0:
  318. return 96 + fastLog2(a.udata[3])
  319. if a.udata[2] != 0:
  320. return 64 + fastLog2(a.udata[2])
  321. if a.udata[1] != 0:
  322. return 32 + fastLog2(a.udata[1])
  323. if a.udata[0] != 0:
  324. return fastLog2(a.udata[0])
  325. proc divMod*(dividend, divisor: Int128): tuple[quotient, remainder: Int128] =
  326. assert(divisor != Zero)
  327. let isNegativeA = isNegative(dividend)
  328. let isNegativeB = isNegative(divisor)
  329. var dividend = abs(dividend)
  330. let divisor = abs(divisor)
  331. if divisor > dividend:
  332. result.quotient = Zero
  333. if isNegativeA:
  334. result.remainder = -dividend
  335. else:
  336. result.remainder = dividend
  337. return
  338. if divisor == dividend:
  339. if isNegativeA xor isNegativeB:
  340. result.quotient = NegOne
  341. else:
  342. result.quotient = One
  343. result.remainder = Zero
  344. return
  345. var denominator = divisor
  346. var quotient = Zero
  347. # Left aligns the MSB of the denominator and the dividend.
  348. let shift = fastLog2(dividend) - fastLog2(denominator)
  349. denominator = denominator shl shift
  350. # Uses shift-subtract algorithm to divide dividend by denominator. The
  351. # remainder will be left in dividend.
  352. for i in 0..shift:
  353. quotient = quotient shl 1
  354. if dividend >= denominator:
  355. dividend -= denominator
  356. quotient = bitor(quotient, One)
  357. denominator = denominator shr 1
  358. if isNegativeA xor isNegativeB:
  359. result.quotient = -quotient
  360. else:
  361. result.quotient = quotient
  362. if isNegativeA:
  363. result.remainder = -dividend
  364. else:
  365. result.remainder = dividend
  366. proc `div`*(a, b: Int128): Int128 =
  367. let (a, b) = divMod(a, b)
  368. return a
  369. proc `mod`*(a, b: Int128): Int128 =
  370. let (a, b) = divMod(a, b)
  371. return b
  372. proc addInt128*(result: var string; value: Int128) =
  373. let initialSize = result.len
  374. if value == Zero:
  375. result.add "0"
  376. elif value == low(Int128):
  377. result.add "-170141183460469231731687303715884105728"
  378. else:
  379. let isNegative = isNegative(value)
  380. var value = abs(value)
  381. while value > Zero:
  382. let (quot, rem) = divMod(value, Ten)
  383. result.add "0123456789"[rem.toInt64]
  384. value = quot
  385. if isNegative:
  386. result.add '-'
  387. var i = initialSize
  388. var j = high(result)
  389. while i < j:
  390. swap(result[i], result[j])
  391. i += 1
  392. j -= 1
  393. proc `$`*(a: Int128): string =
  394. result.addInt128(a)
  395. proc parseDecimalInt128*(arg: string, pos: int = 0): Int128 =
  396. assert(pos < arg.len)
  397. assert(arg[pos] in {'-', '0'..'9'})
  398. var isNegative = false
  399. var pos = pos
  400. if arg[pos] == '-':
  401. isNegative = true
  402. pos += 1
  403. result = Zero
  404. while pos < arg.len and arg[pos] in '0'..'9':
  405. result = result * Ten
  406. result.inc(uint32(arg[pos]) - uint32('0'))
  407. pos += 1
  408. if isNegative:
  409. result = -result
  410. # fluff
  411. proc `<`*(a: Int128, b: BiggestInt): bool =
  412. cmp(a, toInt128(b)) < 0
  413. proc `<`*(a: BiggestInt, b: Int128): bool =
  414. cmp(toInt128(a), b) < 0
  415. proc `<=`*(a: Int128, b: BiggestInt): bool =
  416. cmp(a, toInt128(b)) <= 0
  417. proc `<=`*(a: BiggestInt, b: Int128): bool =
  418. cmp(toInt128(a), b) <= 0
  419. proc `==`*(a: Int128, b: BiggestInt): bool =
  420. a == toInt128(b)
  421. proc `==`*(a: BiggestInt, b: Int128): bool =
  422. toInt128(a) == b
  423. proc `-`*(a: BiggestInt, b: Int128): Int128 =
  424. toInt128(a) - b
  425. proc `-`*(a: Int128, b: BiggestInt): Int128 =
  426. a - toInt128(b)
  427. proc `+`*(a: BiggestInt, b: Int128): Int128 =
  428. toInt128(a) + b
  429. proc `+`*(a: Int128, b: BiggestInt): Int128 =
  430. a + toInt128(b)
  431. proc toFloat64*(arg: Int128): float64 =
  432. let isNegative = isNegative(arg)
  433. let arg = abs(arg)
  434. let a = float64(bitconcat(arg.udata[1], arg.udata[0]))
  435. let b = float64(bitconcat(arg.udata[3], arg.udata[2]))
  436. result = a + 18446744073709551616'f64 * b # a + 2^64 * b
  437. if isNegative:
  438. result = -result
  439. proc ldexp(x: float64, exp: cint): float64 {.importc: "ldexp", header: "<math.h>".}
  440. template bitor(a, b, c: Int128): Int128 = bitor(bitor(a, b), c)
  441. proc toInt128*(arg: float64): Int128 =
  442. let isNegative = arg < 0
  443. let v0 = ldexp(abs(arg), -100)
  444. let w0 = uint64(trunc(v0))
  445. let v1 = ldexp(v0 - float64(w0), 50)
  446. let w1 = uint64(trunc(v1))
  447. let v2 = ldexp(v1 - float64(w1), 50)
  448. let w2 = uint64(trunc(v2))
  449. let res = bitor(toInt128(w0) shl 100, toInt128(w1) shl 50, toInt128(w2))
  450. if isNegative:
  451. return -res
  452. else:
  453. return res
  454. proc maskUInt64*(arg: Int128): Int128 {.noinit, inline.} =
  455. result.udata[0] = arg.udata[0]
  456. result.udata[1] = arg.udata[1]
  457. result.udata[2] = 0
  458. result.udata[3] = 0
  459. proc maskUInt32*(arg: Int128): Int128 {.noinit, inline.} =
  460. result.udata[0] = arg.udata[0]
  461. result.udata[1] = 0
  462. result.udata[2] = 0
  463. result.udata[3] = 0
  464. proc maskUInt16*(arg: Int128): Int128 {.noinit, inline.} =
  465. result.udata[0] = arg.udata[0] and 0xffff
  466. result.udata[1] = 0
  467. result.udata[2] = 0
  468. result.udata[3] = 0
  469. proc maskUInt8*(arg: Int128): Int128 {.noinit, inline.} =
  470. result.udata[0] = arg.udata[0] and 0xff
  471. result.udata[1] = 0
  472. result.udata[2] = 0
  473. result.udata[3] = 0
  474. proc maskBytes*(arg: Int128, numbytes: int): Int128 {.noinit.} =
  475. case numbytes
  476. of 1:
  477. return maskUInt8(arg)
  478. of 2:
  479. return maskUInt16(arg)
  480. of 4:
  481. return maskUInt32(arg)
  482. of 8:
  483. return maskUInt64(arg)
  484. else:
  485. assert(false, "masking only implemented for 1, 2, 4 and 8 bytes")