more custom literal tests and overflow check
This commit is contained in:
parent
e374311f70
commit
ea02d7db68
24
stint/io.nim
24
stint/io.nim
|
@ -333,7 +333,7 @@ func toString*[bits: static[int]](num: StUint[bits], radix: static[uint8] = 10):
|
||||||
|
|
||||||
reverse(result)
|
reverse(result)
|
||||||
|
|
||||||
func toString*[bits: static[int]](num: StInt[bits], radix: static[int8] = 10): string =
|
func toString*[bits: static[int]](num: StInt[bits], radix: static[uint8] = 10): string =
|
||||||
## Convert a Stint or StUint to string.
|
## Convert a Stint or StUint to string.
|
||||||
## In case of negative numbers:
|
## In case of negative numbers:
|
||||||
## - they are prefixed with "-" for base 10.
|
## - they are prefixed with "-" for base 10.
|
||||||
|
@ -466,26 +466,16 @@ template toBytesBE*[bits: static[int]](n: StInt[bits]): array[bits div 8, byte]
|
||||||
|
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
func getRadix(s: static string): uint8 {.compileTime.} =
|
include
|
||||||
if s.len <= 2:
|
./private/custom_literal
|
||||||
return 10
|
|
||||||
|
|
||||||
# maybe have prefix have prefix
|
|
||||||
if s[0] != '0':
|
|
||||||
return 10
|
|
||||||
|
|
||||||
if s[1] == 'b':
|
|
||||||
return 2
|
|
||||||
|
|
||||||
if s[1] == 'o':
|
|
||||||
return 8
|
|
||||||
|
|
||||||
if s[1] == 'x':
|
|
||||||
return 16
|
|
||||||
|
|
||||||
func customLiteral*(T: type SomeBigInteger, s: static string): T =
|
func customLiteral*(T: type SomeBigInteger, s: static string): T =
|
||||||
when s.len == 0:
|
when s.len == 0:
|
||||||
doAssert(false, "customLiteral cannot accept param with zero length")
|
doAssert(false, "customLiteral cannot accept param with zero length")
|
||||||
|
|
||||||
const radix = getRadix(s)
|
const radix = getRadix(s)
|
||||||
|
type TT = T
|
||||||
|
when isOverflow(TT, s, radix):
|
||||||
|
{.error: "Stint custom literal overlow detected" .}
|
||||||
|
|
||||||
parse(s, T, radix)
|
parse(s, T, radix)
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
# Stint
|
||||||
|
# Copyright 2018-2023 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.
|
||||||
|
|
||||||
|
func getRadix(s: static string): uint8 {.compileTime.} =
|
||||||
|
if s.len <= 2:
|
||||||
|
return 10
|
||||||
|
|
||||||
|
# maybe have prefix have prefix
|
||||||
|
if s[0] != '0':
|
||||||
|
return 10
|
||||||
|
|
||||||
|
if s[1] == 'b':
|
||||||
|
return 2
|
||||||
|
|
||||||
|
if s[1] == 'o':
|
||||||
|
return 8
|
||||||
|
|
||||||
|
if s[1] == 'x':
|
||||||
|
return 16
|
||||||
|
|
||||||
|
func stripPrefix(s: string): string {.compileTime.} =
|
||||||
|
if s[0] != '0':
|
||||||
|
return s
|
||||||
|
if s[1] in {'b', 'o', 'x'}:
|
||||||
|
return s[2 .. ^1]
|
||||||
|
s
|
||||||
|
|
||||||
|
func stripLeadingZeros(value: string): string {.compileTime.} =
|
||||||
|
var cidx = 0
|
||||||
|
# ignore the last character so we retain '0' on zero value
|
||||||
|
while cidx < value.len - 1 and value[cidx] == '0':
|
||||||
|
cidx.inc
|
||||||
|
value[cidx .. ^1]
|
||||||
|
|
||||||
|
func isOverflow(T: type SomeBigInteger, s: static string, radix: static uint8): bool {.compileTime.} =
|
||||||
|
# a stupid but effective overflow detection
|
||||||
|
# it's a compiletime check anyway
|
||||||
|
let tmp = parse(s, T, radix)
|
||||||
|
let litStr = tmp.toString(radix)
|
||||||
|
let normalizedSrc = s.stripPrefix.stripLeadingZeros
|
||||||
|
litStr != normalizedSrc
|
|
@ -6,7 +6,12 @@
|
||||||
#
|
#
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import ../stint, unittest
|
import
|
||||||
|
../stint,
|
||||||
|
unittest
|
||||||
|
|
||||||
|
template reject(code: untyped) =
|
||||||
|
static: assert(not compiles(code))
|
||||||
|
|
||||||
suite "new features":
|
suite "new features":
|
||||||
test "custom literal":
|
test "custom literal":
|
||||||
|
@ -19,6 +24,8 @@ suite "new features":
|
||||||
let
|
let
|
||||||
x = 0b111100011'u128
|
x = 0b111100011'u128
|
||||||
y = 0o777766666'u256
|
y = 0o777766666'u256
|
||||||
|
z = 0x1122334455667788991011121314151617181920aabbccddeeffb1b2b3b4b500'u256
|
||||||
|
w = 340282366920938463463374607431768211455'u128
|
||||||
|
|
||||||
check:
|
check:
|
||||||
a == 0xabcdef0123456.u128
|
a == 0xabcdef0123456.u128
|
||||||
|
@ -27,3 +34,21 @@ suite "new features":
|
||||||
d == -50000.i256
|
d == -50000.i256
|
||||||
x == 0b111100011.u128
|
x == 0b111100011.u128
|
||||||
y == 0o777766666.u256
|
y == 0o777766666.u256
|
||||||
|
z == UInt256.fromHex("0x1122334455667788991011121314151617181920aabbccddeeffb1b2b3b4b500")
|
||||||
|
w == UInt128.fromDecimal("340282366920938463463374607431768211455")
|
||||||
|
|
||||||
|
test "custom literal overflow":
|
||||||
|
reject:
|
||||||
|
const
|
||||||
|
z = 0x1122334455667788991011121314151617181920aabbccddeeffb1b2b3b4b5700'u256
|
||||||
|
doAssert(false)
|
||||||
|
|
||||||
|
reject:
|
||||||
|
let
|
||||||
|
z = 0x1122334455667788991011121314151617181920aabbccddeeffb1b2b3b4b5700'u256
|
||||||
|
doAssert(false)
|
||||||
|
|
||||||
|
reject:
|
||||||
|
const
|
||||||
|
w = 1122334455667788991011121314151617181920'u128
|
||||||
|
doAssert(false)
|
||||||
|
|
Loading…
Reference in New Issue