nim-stint/stint/private/datatypes.nim

155 lines
4.5 KiB
Nim
Raw Normal View History

# Stint
# 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.
2020-06-12 16:37:02 +00:00
import
# Status lib
stew/bitops2
2020-06-12 16:37:02 +00:00
when sizeof(int) == 8 and not defined(Stint32):
type Word* = uint64
else:
2020-06-12 16:37:02 +00:00
type Word* = uint32
2020-06-12 17:23:03 +00:00
const WordBitWidth* = sizeof(Word) * 8
2020-06-12 16:37:02 +00:00
func wordsRequired*(bits: int): int {.compileTime.} =
## Compute the number of limbs required
## from the **announced** bit length
(bits + WordBitWidth - 1) div WordBitWidth
type
2020-06-12 17:01:05 +00:00
Limbs*[N: static int] = array[N, Word]
2018-04-25 10:52:00 +00:00
StUint*[bits: static[int]] = object
2020-06-12 16:37:02 +00:00
## Stack-based integer
## Unsigned
limbs*: Limbs[bits.wordsRequired]
StInt*[bits: static[int]] = object
2020-06-12 16:37:02 +00:00
## Stack-based integer
## Signed
limbs*: Limbs[bits.wordsRequired]
Carry* = uint8 # distinct range[0'u8 .. 1]
Borrow* = uint8 # distinct range[0'u8 .. 1]
SomeBigInteger*[bits: static[int]] = Stuint[bits]|Stint[bits]
2020-06-12 16:37:02 +00:00
const GCC_Compatible* = defined(gcc) or defined(clang) or defined(llvm_gcc)
const X86* = defined(amd64) or defined(i386)
2020-06-12 16:37:02 +00:00
when sizeof(int) == 8 and GCC_Compatible:
type
uint128*{.importc: "unsigned __int128".} = object
2022-04-07 07:52:36 +00:00
# Accessors
# --------------------------------------------------------
2019-10-08 13:11:08 +00:00
template leastSignificantWord*(num: SomeInteger): auto =
num
func leastSignificantWord*(a: SomeBigInteger): auto {.inline.} =
2020-06-12 16:37:02 +00:00
when cpuEndian == littleEndian:
a.limbs[0]
else:
a.limbs[^1]
func mostSignificantWord*(a: SomeBigInteger): auto {.inline.} =
2020-06-12 16:37:02 +00:00
when cpuEndian == littleEndian:
a.limbs[^1]
else:
a.limbs[0]
2020-06-12 17:01:05 +00:00
# Iterations
# --------------------------------------------------------
iterator leastToMostSig*(a: SomeBigInteger): Word =
2020-06-12 17:01:05 +00:00
## Iterate from least to most significant word
when cpuEndian == littleEndian:
for i in 0 ..< a.limbs.len:
yield a.limbs[i]
2020-06-12 17:01:05 +00:00
else:
for i in countdown(a.limbs.len-1, 0):
yield a.limbs[i]
2020-06-12 17:01:05 +00:00
iterator leastToMostSig*(a: var SomeBigInteger): var Word =
2020-06-12 17:01:05 +00:00
## Iterate from least to most significant word
when cpuEndian == littleEndian:
for i in 0 ..< a.limbs.len:
yield a.limbs[i]
2020-06-12 17:01:05 +00:00
else:
for i in countdown(a.limbs.len-1, 0):
yield a.limbs[i]
2020-06-12 17:01:05 +00:00
iterator leastToMostSig*(a, b: SomeBigInteger): (Word, Word) =
2020-06-12 17:01:05 +00:00
## Iterate from least to most significant word
when cpuEndian == littleEndian:
for i in 0 ..< a.limbs.len:
yield (a.limbs[i], b.limbs[i])
2020-06-12 17:01:05 +00:00
else:
for i in countdown(a.limbs.len-1, 0):
yield (a.limbs[i], b.limbs[i])
2020-06-12 17:01:05 +00:00
iterator leastToMostSig*[aBits, bBits](a: var SomeBigInteger[aBits], b: SomeBigInteger[bBits]): (var Word, Word) =
2020-06-12 17:01:05 +00:00
## Iterate from least to most significant word
when cpuEndian == littleEndian:
for i in 0 ..< min(a.limbs.len, b.limbs.len):
yield (a.limbs[i], b.limbs[i])
2020-06-12 17:01:05 +00:00
else:
for i in countdown(min(aLimbs.len, b.limbs.len)-1, 0):
yield (a.limbs[i], b.limbs[i])
2020-06-12 17:23:03 +00:00
iterator leastToMostSig*(c: var SomeBigInteger, a, b: SomeBigInteger): (var Word, Word, Word) =
2020-06-12 17:23:03 +00:00
## Iterate from least to most significant word
when cpuEndian == littleEndian:
for i in 0 ..< a.limbs.len:
yield (c.limbs[i], a.limbs[i], b.limbs[i])
else:
for i in countdown(a.limbs.len-1, 0):
yield (c.limbs[i], a.limbs[i], b.limbs[i])
iterator mostToLeastSig*(a: SomeBigInteger): Word =
## Iterate from most to least significant word
when cpuEndian == bigEndian:
for i in 0 ..< a.limbs.len:
yield a.limbs[i]
2020-06-12 17:23:03 +00:00
else:
for i in countdown(a.limbs.len-1, 0):
yield a.limbs[i]
2020-06-12 18:05:40 +00:00
import std/macros
proc replaceNodes(ast: NimNode, what: NimNode, by: NimNode): NimNode =
# Replace "what" ident node by "by"
proc inspect(node: NimNode): NimNode =
case node.kind:
of {nnkIdent, nnkSym}:
if node.eqIdent(what):
return by
return node
of nnkEmpty:
return node
of nnkLiterals:
return node
else:
var rTree = node.kind.newTree()
for child in node:
rTree.add inspect(child)
return rTree
result = inspect(ast)
macro staticFor*(idx: untyped{nkIdent}, start, stopEx: static int, body: untyped): untyped =
## staticFor [min inclusive, max exclusive)
result = newStmtList()
for i in start ..< stopEx:
result.add nnkBlockStmt.newTree(
ident("unrolledIter_" & $idx & $i),
body.replaceNodes(idx, newLit i)
)