Bigint fixes

* Native and big integer comparison
* Refuse to serialize negative big ints for now
This commit is contained in:
Emery Hemingway 2021-06-04 11:39:52 +02:00
parent d63dfad954
commit bfb0825721
2 changed files with 23 additions and 13 deletions

View File

@ -55,7 +55,12 @@ proc `<`(x, y: string | seq[byte]): bool =
proc `<`*[T](x, y: Preserve[T]): bool =
if x.kind != y.kind:
result = x.kind < y.kind
if x.kind == pkSignedInteger and y.kind == pkBigInteger:
result = x.int < y.bigint
elif x.kind == pkBigInteger and y.kind == pkSignedInteger:
result = x.bigint < y.int
else:
result = x.kind < y.kind
else:
case x.kind
of pkBoolean:
@ -126,6 +131,7 @@ proc hash*[T](prs: Preserve[T]): Hash =
of pkSignedInteger:
h = h !& hash(prs.int)
of pkBigInteger:
h = h !& hash(prs.bigint.flags)
h = h !& hash(prs.bigint)
of pkString:
h = h !& hash(prs.string)
@ -265,12 +271,13 @@ proc write*[T](str: Stream; prs: Preserve[T]) =
inc(bitCount)
var byteCount = (bitCount + 8) div 8
str.write(0xa0'u8 or (byteCount - 1))
proc write(n: uint8, i: BiggestInt) =
proc write(n: uint8; i: BiggestInt) =
if n > 0:
write(n.pred, i shr 8)
str.write(i.uint8)
write(byteCount, prs.int)
of pkBigInteger:
doAssert(Negative notin prs.bigint.flags, "negative big integers not implemented")
var bytes = newSeqOfCap[uint8](prs.bigint.limbs.len * 4)
var begun = false
for i in countdown(prs.bigint.limbs.high, 0):
@ -285,8 +292,6 @@ proc write*[T](str: Stream; prs: Preserve[T]) =
else:
str.write(0xb0'u8)
str.writeVarint(bytes.len)
if Negative in prs.bigint.flags:
bytes[0] = uint8(- bytes[0].int8)
str.write(cast[string](bytes))
of pkString:
str.write(0xb1'u8)
@ -364,7 +369,7 @@ proc parsePreserve*(s: Stream): Preserve[void] =
let len = s.readVarint()
result.symbol = s.readStr(len)
of 0xb4:
result = Preserve[void](kind: pkRecord #[, label: s.parsePreserve()]#)
result = Preserve[void](kind: pkRecord)
while s.peekUint8() != endMarker:
result.record.add(s.parsePreserve())
discard s.readUint8()
@ -389,12 +394,9 @@ proc parsePreserve*(s: Stream): Preserve[void] =
discard s.readUint8()
of 0xb0:
let len = s.readVarint()
let initial = s.readInt8()
result = Preserve[void](kind: pkBigInteger, bigint: initBigInt(initial))
for _ in 2..len:
result = Preserve[void](kind: pkBigInteger)
for _ in 1..len:
result.bigint = (result.bigint shl 8) + s.readUint8().int32
if initial < 0:
result.bigint.flags = {Negative}
else:
case 0xf0 and tag
of 0x90:
@ -422,7 +424,15 @@ proc toPreserve*(n: SomeInteger): Preserve[void] =
Preserve[void](kind: pkSignedInteger, int: n.BiggestInt)
proc toPreserve*(n: BigInt): Preserve[void] =
Preserve[void](kind: pkBigInteger, bigint: n)
if initBigInt(low(BiggestInt)) < n and n < initBigInt(high(BiggestInt)):
var tmp: BiggestUint
for limb in n.limbs:
tmp = (tmp shl 32) or limb
if Negative in n.flags:
tmp = (not tmp) + 1
result = Preserve[void](kind: pkSignedInteger, int: cast[BiggestInt](tmp))
else:
result = Preserve[void](kind: pkBigInteger, bigint: n)
proc toPreserve*(s: string): Preserve[void] =
Preserve[void](kind: pkString, string: s)

View File

@ -50,8 +50,8 @@ suite "native":
suite "big":
let testVectors = @[
("87112285931760246646623899502532662132736", "B012010000000000000000000000000000000000"),
("-87112285931760246646623899502532662132736", "B012FF0000000000000000000000000000000000"),
("87112285931760246646623899502532662132736",
"B012010000000000000000000000000000000000"),
]
for (decimals, hex) in testVectors: