Add parseUInt and parseBiggestUInt functions to stdlib (parseutils, strutils)

This commit is contained in:
Anatoly Galiulin
2016-03-30 17:34:41 +06:00
parent 3b732259c0
commit 9aa845c6b6
3 changed files with 80 additions and 0 deletions

View File

@@ -234,6 +234,57 @@ proc parseInt*(s: string, number: var int, start = 0): int {.
elif result != 0:
number = int(res)
# overflowChecks doesn't work with uint64
proc rawParseUInt(s: string, b: var uint64, start = 0): int =
var
res = 0'u64
prev = 0'u64
i = start
if s[i] == '+': inc(i) # Allow
if s[i] in {'0'..'9'}:
b = 0
while s[i] in {'0'..'9'}:
prev = res
res = res * 10 + (ord(s[i]) - ord('0')).uint64
if prev > res:
return 0 # overflowChecks emulation
inc(i)
while s[i] == '_': inc(i) # underscores are allowed and ignored
b = res
result = i - start
proc parseBiggestUInt*(s: string, number: var uint64, start = 0): int {.
rtl, extern: "npuParseBiggestUInt", noSideEffect.} =
## parses an unsigned integer starting at `start` and stores the value into `number`.
## Result is the number of processed chars or 0 if there is no integer or overflow detected.
var res: uint64
# use 'res' for exception safety (don't write to 'number' in case of an
# overflow exception):
result = rawParseUInt(s, res, start)
number = res
# Workaround for high(uint)
proc highUInt(): uint64 =
when sizeof(uint) == 4:
0xFFFFFFFF'u64
elif sizeof(uint) == 8:
0xFFFFFFFFFFFFFFFF'u64
else:
{.fatal: "Unknoun uint size: " & $sizeof(uint).}
proc parseUInt*(s: string, number: var uint, start = 0): int {.
rtl, extern: "npuParseUInt", noSideEffect.} =
## parses an unsigned integer starting at `start` and stores the value into `number`.
## Result is the number of processed chars or 0 if there is no integer.
## Result is the number of processed chars or 0 if there is no integer or overflow detected.
var res: uint64
result = parseBiggestUInt(s, res, start)
if (sizeof(uint) <= 4) and
(res > highUInt()):
raise newException(OverflowError, "overflow")
elif result != 0:
number = uint(res)
proc parseBiggestFloat*(s: string, number: var BiggestFloat, start = 0): int {.
magic: "ParseBiggestFloat", importc: "nimParseBiggestFloat", noSideEffect.}
## parses a float starting at `start` and stores the value into `number`.

View File

@@ -560,6 +560,24 @@ proc parseBiggestInt*(s: string): BiggestInt {.noSideEffect, procvar,
if L != s.len or L == 0:
raise newException(ValueError, "invalid integer: " & s)
proc parseUInt*(s: string): uint {.noSideEffect, procvar,
rtl, extern: "nsuParseUInt".} =
## Parses a decimal unsigned integer value contained in `s`.
##
## If `s` is not a valid integer, `ValueError` is raised.
var L = parseutils.parseUInt(s, result, 0)
if L != s.len or L == 0:
raise newException(ValueError, "invalid unsigned integer: " & s)
proc parseBiggestUInt*(s: string): uint64 {.noSideEffect, procvar,
rtl, extern: "nsuParseBiggestUInt".} =
## Parses a decimal unsigned integer value contained in `s`.
##
## If `s` is not a valid integer, `ValueError` is raised.
var L = parseutils.parseBiggestUInt(s, result, 0)
if L != s.len or L == 0:
raise newException(ValueError, "invalid unsigned integer: " & s)
proc parseFloat*(s: string): float {.noSideEffect, procvar,
rtl, extern: "nsuParseFloat".} =
## Parses a decimal floating point value contained in `s`. If `s` is not

View File

@@ -0,0 +1,11 @@
discard """
action: run
"""
import unittest, strutils
suite "parseutils":
test "uint":
check: parseBiggestUInt("0") == 0'u64
check: parseBiggestUInt("18446744073709551615") == 0xFFFF_FFFF_FFFF_FFFF'u64
expect(ValueError):
discard parseBiggestUInt("18446744073709551616")