summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
authorAnatoly Galiulin <galiulin.anatoly@gmail.com>2016-03-30 17:34:41 +0600
committerAnatoly Galiulin <galiulin.anatoly@gmail.com>2016-03-30 17:38:57 +0600
commit9aa845c6b677dc1a01533dcf02e29acb971a13ee (patch)
treef80b7e0cbfc4a7f0e60b3351223a8fb26f607085 /lib
parent3b732259c04dcb9ee763caf9f7697677624b7dc3 (diff)
downloadNim-9aa845c6b677dc1a01533dcf02e29acb971a13ee.tar.gz
Add parseUInt and parseBiggestUInt functions to stdlib (parseutils, strutils)
Diffstat (limited to 'lib')
-rw-r--r--lib/pure/parseutils.nim51
-rw-r--r--lib/pure/strutils.nim18
2 files changed, 69 insertions, 0 deletions
diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim
index 698bde42a..66bdadb29 100644
--- a/lib/pure/parseutils.nim
+++ b/lib/pure/parseutils.nim
@@ -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`.
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index f2c1e77e1..eebadf4c0 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -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