mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
* This adds `parseutils.parseSize`, an inverse to `strutils.formatSize` which has existed since 2017. It is useful for parsing the compiler's own output logs (like SuccessX) or many other scenarios where "human readable" units have been chosen. The doc comment and tests explain accepted syntax in detail. Big units lead to small numbers, often with a fractional part, but we parse into an `int64` since that is what `formatSize` stringifies and this is an inverse over partial function slots. Although metric prefixes z & y for zettabyte & yottabyte are accepted, these will saturate the result at `int64.high` unless the qualified number is a small fraction. This should not be much of a problem until such sizes are common (at which point another overload with the parse result either `float64` or `int128` could be added). Tests avoids `test()` because of a weakly related static: test() failure as mentioned in https://github.com/nim-lang/Nim/pull/21325. This is a more elemental VM failure. As such, it needs its own failure exhibition issue that is a smaller test case. (I am working on that, but unless there is a burning need to `parseSize` at compile-time before run-time it need not hold up this PR.) * This worked with `int` but fails with `int64`. Try for green tests. * Lift 2-result matching into a `checkParseSize` template and format as a table of input & 2 expected outputs which seems nicer and to address https://github.com/nim-lang/Nim/pull/21349#pullrequestreview-1294407679 * Fix (probably) the i386 trouble by using `int64` consistently. * Improve documentation by mentioning saturation. * Improve documentation with `runnableExamples` and a little more detail in the main doc comment based on excellent code review by @juancarlospaco: https://github.com/nim-lang/Nim/pull/21349#pullrequestreview-1294564155 * Address some more @juancarlospaco code review concerns. * Remove a stray space. * Mention milli-bytes in docs to maybe help clarify why wild conventions are so prone to going case-insensitive-metric. * Add some parens.
101 lines
3.5 KiB
Nim
101 lines
3.5 KiB
Nim
discard """
|
|
targets: "c cpp"
|
|
"""
|
|
|
|
import std/[parseutils, sequtils, sugar, formatfloat]
|
|
import std/assertions
|
|
|
|
proc test() =
|
|
let input = "$test{} $this is ${an{ example}} "
|
|
let expected = @[(ikVar, "test"), (ikStr, "{} "), (ikVar, "this"),
|
|
(ikStr, " is "), (ikExpr, "an{ example}"), (ikStr, " ")]
|
|
doAssert toSeq(interpolatedFragments(input)) == expected
|
|
|
|
var value = 0
|
|
discard parseHex("0x38", value)
|
|
doAssert value == 56
|
|
|
|
value = -1
|
|
doAssert(parseSaturatedNatural("848", value) == 3)
|
|
doAssert value == 848
|
|
|
|
value = -1
|
|
discard parseSaturatedNatural("84899999999999999999324234243143142342135435342532453", value)
|
|
doAssert value == high(int)
|
|
|
|
value = -1
|
|
discard parseSaturatedNatural("9223372036854775808", value)
|
|
doAssert value == high(int)
|
|
|
|
value = -1
|
|
discard parseSaturatedNatural("9223372036854775807", value)
|
|
doAssert value == high(int)
|
|
|
|
value = -1
|
|
discard parseSaturatedNatural("18446744073709551616", value)
|
|
doAssert value == high(int)
|
|
|
|
value = -1
|
|
discard parseSaturatedNatural("18446744073709551615", value)
|
|
doAssert value == high(int)
|
|
|
|
value = -1
|
|
doAssert(parseSaturatedNatural("1_000_000", value) == 9)
|
|
doAssert value == 1_000_000
|
|
|
|
var i64Value: int64
|
|
discard parseBiggestInt("9223372036854775807", i64Value)
|
|
doAssert i64Value == 9223372036854775807
|
|
|
|
block:
|
|
var f: float
|
|
let res = collect:
|
|
for x in ["9.123456789012345+","11.123456789012345+","9.123456789012345-","8.123456789012345+","9.12345678901234-","9.123456789012345"]:
|
|
(parseFloat(x, f, 0), $f)
|
|
doAssert res == @[(17, "9.123456789012344"), (18, "11.123456789012344"),
|
|
(17, "9.123456789012344"), (17, "8.123456789012344"),
|
|
(16, "9.12345678901234"), (17, "9.123456789012344")]
|
|
|
|
test()
|
|
static: test()
|
|
|
|
block: # With this included, static: test() crashes the compiler (from a
|
|
# VM problem with parseSize calling parseFloat).
|
|
var sz: int64
|
|
template checkParseSize(s, expectLen, expectVal) =
|
|
if (let got = parseSize(s, sz); got != expectLen):
|
|
raise newException(IOError, "got len " & $got & " != " & $expectLen)
|
|
if sz != expectVal:
|
|
raise newException(IOError, "got sz " & $sz & " != " & $expectVal)
|
|
# STRING LEN SZ
|
|
# Good, complete parses
|
|
checkParseSize "1 b" , 4, 1
|
|
checkParseSize "1 B" , 4, 1
|
|
checkParseSize "1k" , 2, 1000
|
|
checkParseSize "1 kib" , 5, 1024
|
|
checkParseSize "1 ki" , 4, 1024
|
|
checkParseSize "1mi" , 3, 1048576
|
|
checkParseSize "1 mi" , 4, 1048576
|
|
checkParseSize "1 mib" , 5, 1048576
|
|
checkParseSize "1 Mib" , 5, 1048576
|
|
checkParseSize "1 MiB" , 5, 1048576
|
|
checkParseSize "1.23GiB", 7, 1320702444 # 1320702443.52 rounded
|
|
checkParseSize "0.001k" , 6, 1
|
|
checkParseSize "0.0004k", 7, 0
|
|
checkParseSize "0.0006k", 7, 1
|
|
# Incomplete parses
|
|
checkParseSize "1 " , 1, 1 # Trailing white IGNORED
|
|
checkParseSize "1 B " , 4, 1 # Trailing white IGNORED
|
|
checkParseSize "1 B/s" , 4, 1 # Trailing junk IGNORED
|
|
checkParseSize "1 kX" , 3, 1000
|
|
checkParseSize "1 kiX" , 4, 1024
|
|
checkParseSize "1j" , 1, 1 # Unknown prefix IGNORED
|
|
checkParseSize "1 jib" , 2, 1 # Unknown prefix post space
|
|
checkParseSize "1 ji" , 3, 1
|
|
# Bad parses; `sz` should stay last good|incomplete value
|
|
checkParseSize "-1b" , 0, 1 # Negative numbers
|
|
checkParseSize "abc" , 0, 1 # Non-numeric
|
|
checkParseSize " 12" , 0, 1 # Leading white
|
|
# Value Edge cases
|
|
checkParseSize "9223372036854775807", 19, int64.high
|