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

View File

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