From bfb0825721fe83390a77324a0d669235a0958358 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Fri, 4 Jun 2021 11:39:52 +0200 Subject: [PATCH] Bigint fixes * Native and big integer comparison * Refuse to serialize negative big ints for now --- src/preserves.nim | 32 +++++++++++++++++++++----------- tests/test_integers.nim | 4 ++-- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/preserves.nim b/src/preserves.nim index d9eaad8..d98eeaa 100644 --- a/src/preserves.nim +++ b/src/preserves.nim @@ -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) diff --git a/tests/test_integers.nim b/tests/test_integers.nim index 93ed728..0950a1b 100644 --- a/tests/test_integers.nim +++ b/tests/test_integers.nim @@ -50,8 +50,8 @@ suite "native": suite "big": let testVectors = @[ - ("87112285931760246646623899502532662132736", "B012010000000000000000000000000000000000"), - ("-87112285931760246646623899502532662132736", "B012FF0000000000000000000000000000000000"), + ("87112285931760246646623899502532662132736", + "B012010000000000000000000000000000000000"), ] for (decimals, hex) in testVectors: