init checks and 'out' parameters (#14521)
* I don't care about observable stores * enforce explicit initializations * cleaner code for the stdlib * stdlib: use explicit initializations * make tests green * algorithm.nim: set result explicitly * remove out parameters and bring the PR into a mergable state * updated the changelog
This commit is contained in:
parent
a9eee6db65
commit
da29222f86
53 changed files with 355 additions and 257 deletions
|
|
@ -187,6 +187,7 @@ proc binarySearch*[T, K](a: openArray[T], key: K,
|
|||
else:
|
||||
return -1
|
||||
|
||||
result = 0
|
||||
if (len and (len - 1)) == 0:
|
||||
# when `len` is a power of 2, a faster shr can be used.
|
||||
var step = len shr 1
|
||||
|
|
|
|||
|
|
@ -395,6 +395,8 @@ proc firstSetBitNim(x: uint64): int {.inline, noSideEffect.} =
|
|||
if k == 0:
|
||||
k = uint32(v shr 32'u32) and 0xFFFFFFFF'u32
|
||||
result = 32
|
||||
else:
|
||||
result = 0
|
||||
result += firstSetBitNim(k)
|
||||
|
||||
proc fastlog2Nim(x: uint32): int {.inline, noSideEffect.} =
|
||||
|
|
|
|||
|
|
@ -417,7 +417,8 @@ proc relativePath*(path, base: string, sep = DirSep): string {.
|
|||
if not sameRoot(path, base):
|
||||
return path
|
||||
|
||||
var f, b: PathIter
|
||||
var f = default PathIter
|
||||
var b = default PathIter
|
||||
var ff = (0, -1)
|
||||
var bb = (0, -1) # (int, int)
|
||||
result = newStringOfCap(path.len)
|
||||
|
|
@ -1053,6 +1054,7 @@ when defined(windows) or defined(posix) or defined(nintendoswitch):
|
|||
assert quoteShellCommand(["aaa", "", "c d"]) == "aaa \"\" \"c d\""
|
||||
|
||||
# can't use `map` pending https://github.com/nim-lang/Nim/issues/8303
|
||||
result = ""
|
||||
for i in 0..<args.len:
|
||||
if i > 0: result.add " "
|
||||
result.add quoteShell(args[i])
|
||||
|
|
@ -2981,7 +2983,7 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noW
|
|||
setLen(result, L)
|
||||
break
|
||||
elif defined(macosx):
|
||||
var size: cuint32
|
||||
var size = cuint32(0)
|
||||
getExecPath1(nil, size)
|
||||
result = newString(int(size))
|
||||
if getExecPath2(result, size):
|
||||
|
|
|
|||
|
|
@ -249,6 +249,7 @@ proc skipWhitespace*(s: string, start = 0): int {.inline.} =
|
|||
doAssert skipWhitespace(" Hello World", 0) == 1
|
||||
doAssert skipWhitespace("Hello World", 5) == 1
|
||||
doAssert skipWhitespace("Hello World", 5) == 2
|
||||
result = 0
|
||||
while start+result < s.len and s[start+result] in Whitespace: inc(result)
|
||||
|
||||
proc skip*(s, token: string, start = 0): int {.inline.} =
|
||||
|
|
@ -260,6 +261,7 @@ proc skip*(s, token: string, start = 0): int {.inline.} =
|
|||
doAssert skip("2019-01-22", "19", 2) == 2
|
||||
doAssert skip("CAPlow", "CAP", 0) == 3
|
||||
doAssert skip("CAPlow", "cap", 0) == 0
|
||||
result = 0
|
||||
while start+result < s.len and result < token.len and
|
||||
s[result+start] == token[result]:
|
||||
inc(result)
|
||||
|
|
@ -270,6 +272,7 @@ proc skipIgnoreCase*(s, token: string, start = 0): int =
|
|||
runnableExamples:
|
||||
doAssert skipIgnoreCase("CAPlow", "CAP", 0) == 3
|
||||
doAssert skipIgnoreCase("CAPlow", "cap", 0) == 3
|
||||
result = 0
|
||||
while start+result < s.len and result < token.len and
|
||||
toLower(s[result+start]) == toLower(token[result]): inc(result)
|
||||
if result != token.len: result = 0
|
||||
|
|
@ -282,6 +285,7 @@ proc skipUntil*(s: string, until: set[char], start = 0): int {.inline.} =
|
|||
doAssert skipUntil("Hello World", {'W', 'e'}, 0) == 1
|
||||
doAssert skipUntil("Hello World", {'W'}, 0) == 6
|
||||
doAssert skipUntil("Hello World", {'W', 'd'}, 0) == 6
|
||||
result = 0
|
||||
while start+result < s.len and s[result+start] notin until: inc(result)
|
||||
|
||||
proc skipUntil*(s: string, until: char, start = 0): int {.inline.} =
|
||||
|
|
@ -293,6 +297,7 @@ proc skipUntil*(s: string, until: char, start = 0): int {.inline.} =
|
|||
doAssert skipUntil("Hello World", 'o', 4) == 0
|
||||
doAssert skipUntil("Hello World", 'W', 0) == 6
|
||||
doAssert skipUntil("Hello World", 'w', 0) == 11
|
||||
result = 0
|
||||
while start+result < s.len and s[result+start] != until: inc(result)
|
||||
|
||||
proc skipWhile*(s: string, toSkip: set[char], start = 0): int {.inline.} =
|
||||
|
|
@ -302,6 +307,7 @@ proc skipWhile*(s: string, toSkip: set[char], start = 0): int {.inline.} =
|
|||
doAssert skipWhile("Hello World", {'H', 'e'}) == 2
|
||||
doAssert skipWhile("Hello World", {'e'}) == 0
|
||||
doAssert skipWhile("Hello World", {'W', 'o', 'r'}, 6) == 3
|
||||
result = 0
|
||||
while start+result < s.len and s[result+start] in toSkip: inc(result)
|
||||
|
||||
proc parseUntil*(s: string, token: var string, until: set[char],
|
||||
|
|
@ -437,7 +443,7 @@ proc parseBiggestInt*(s: string, number: var BiggestInt, start = 0): int {.
|
|||
var res: BiggestInt
|
||||
doAssert parseBiggestInt("9223372036854775807", res, 0) == 19
|
||||
doAssert res == 9223372036854775807
|
||||
var res: BiggestInt
|
||||
var res = BiggestInt(0)
|
||||
# use 'res' for exception safety (don't write to 'number' in case of an
|
||||
# overflow exception):
|
||||
result = rawParseInt(s, res, start)
|
||||
|
|
@ -455,7 +461,7 @@ proc parseInt*(s: string, number: var int, start = 0): int {.
|
|||
doAssert res == 2019
|
||||
doAssert parseInt("2019", res, 2) == 2
|
||||
doAssert res == 19
|
||||
var res: BiggestInt
|
||||
var res = BiggestInt(0)
|
||||
result = parseBiggestInt(s, res, start)
|
||||
when sizeof(int) <= 4:
|
||||
if res < low(int) or res > high(int):
|
||||
|
|
@ -518,7 +524,7 @@ proc parseBiggestUInt*(s: string, number: var BiggestUInt, start = 0): int {.
|
|||
doAssert res == 12
|
||||
doAssert parseBiggestUInt("1111111111111111111", res, 0) == 19
|
||||
doAssert res == 1111111111111111111'u64
|
||||
var res: BiggestUInt
|
||||
var res = BiggestUInt(0)
|
||||
# use 'res' for exception safety (don't write to 'number' in case of an
|
||||
# overflow exception):
|
||||
result = rawParseUInt(s, res, start)
|
||||
|
|
@ -536,7 +542,7 @@ proc parseUInt*(s: string, number: var uint, start = 0): int {.
|
|||
doAssert res == 3450
|
||||
doAssert parseUInt("3450", res, 2) == 2
|
||||
doAssert res == 50
|
||||
var res: BiggestUInt
|
||||
var res = BiggestUInt(0)
|
||||
result = parseBiggestUInt(s, res, start)
|
||||
when sizeof(BiggestUInt) > sizeof(uint) and sizeof(uint) <= 4:
|
||||
if res > 0xFFFF_FFFF'u64:
|
||||
|
|
@ -563,7 +569,7 @@ proc parseFloat*(s: string, number: var float, start = 0): int {.
|
|||
doAssert res == 32.57
|
||||
doAssert parseFloat("32.57", res, 3) == 2
|
||||
doAssert res == 57.00
|
||||
var bf: BiggestFloat
|
||||
var bf = BiggestFloat(0.0)
|
||||
result = parseBiggestFloat(s, bf, start)
|
||||
if result != 0:
|
||||
number = bf
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ proc next*(it: var PathIter; x: string): (int, int) =
|
|||
it.notFirst = true
|
||||
|
||||
iterator dirs(x: string): (int, int) =
|
||||
var it: PathIter
|
||||
var it = default PathIter
|
||||
while hasNext(it, x): yield next(it, x)
|
||||
|
||||
proc isDot(x: string; bounds: (int, int)): bool =
|
||||
|
|
|
|||
|
|
@ -1103,6 +1103,7 @@ proc parseInt*(s: string): int {.noSideEffect,
|
|||
## If `s` is not a valid integer, `ValueError` is raised.
|
||||
runnableExamples:
|
||||
doAssert parseInt("-0042") == -42
|
||||
result = 0
|
||||
let L = parseutils.parseInt(s, result, 0)
|
||||
if L != s.len or L == 0:
|
||||
raise newException(ValueError, "invalid integer: " & s)
|
||||
|
|
@ -1112,6 +1113,7 @@ proc parseBiggestInt*(s: string): BiggestInt {.noSideEffect,
|
|||
## Parses a decimal integer value contained in `s`.
|
||||
##
|
||||
## If `s` is not a valid integer, `ValueError` is raised.
|
||||
result = BiggestInt(0)
|
||||
let L = parseutils.parseBiggestInt(s, result, 0)
|
||||
if L != s.len or L == 0:
|
||||
raise newException(ValueError, "invalid integer: " & s)
|
||||
|
|
@ -1121,6 +1123,7 @@ proc parseUInt*(s: string): uint {.noSideEffect,
|
|||
## Parses a decimal unsigned integer value contained in `s`.
|
||||
##
|
||||
## If `s` is not a valid integer, `ValueError` is raised.
|
||||
result = uint(0)
|
||||
let L = parseutils.parseUInt(s, result, 0)
|
||||
if L != s.len or L == 0:
|
||||
raise newException(ValueError, "invalid unsigned integer: " & s)
|
||||
|
|
@ -1130,6 +1133,7 @@ proc parseBiggestUInt*(s: string): BiggestUInt {.noSideEffect,
|
|||
## Parses a decimal unsigned integer value contained in `s`.
|
||||
##
|
||||
## If `s` is not a valid integer, `ValueError` is raised.
|
||||
result = BiggestUInt(0)
|
||||
let L = parseutils.parseBiggestUInt(s, result, 0)
|
||||
if L != s.len or L == 0:
|
||||
raise newException(ValueError, "invalid unsigned integer: " & s)
|
||||
|
|
@ -1143,6 +1147,7 @@ proc parseFloat*(s: string): float {.noSideEffect,
|
|||
runnableExamples:
|
||||
doAssert parseFloat("3.14") == 3.14
|
||||
doAssert parseFloat("inf") == 1.0/0
|
||||
result = 0.0
|
||||
let L = parseutils.parseFloat(s, result, 0)
|
||||
if L != s.len or L == 0:
|
||||
raise newException(ValueError, "invalid float: " & s)
|
||||
|
|
@ -1161,6 +1166,7 @@ proc parseBinInt*(s: string): int {.noSideEffect,
|
|||
doAssert a.parseBinInt() == 53
|
||||
doAssert b.parseBinInt() == 7
|
||||
|
||||
result = 0
|
||||
let L = parseutils.parseBin(s, result, 0)
|
||||
if L != s.len or L == 0:
|
||||
raise newException(ValueError, "invalid binary integer: " & s)
|
||||
|
|
@ -1172,6 +1178,7 @@ proc parseOctInt*(s: string): int {.noSideEffect,
|
|||
## If `s` is not a valid oct integer, `ValueError` is raised. `s` can have one
|
||||
## of the following optional prefixes: ``0o``, ``0O``. Underscores within
|
||||
## `s` are ignored.
|
||||
result = 0
|
||||
let L = parseutils.parseOct(s, result, 0)
|
||||
if L != s.len or L == 0:
|
||||
raise newException(ValueError, "invalid oct integer: " & s)
|
||||
|
|
@ -1183,6 +1190,7 @@ proc parseHexInt*(s: string): int {.noSideEffect,
|
|||
## If `s` is not a valid hex integer, `ValueError` is raised. `s` can have one
|
||||
## of the following optional prefixes: ``0x``, ``0X``, ``#``. Underscores
|
||||
## within `s` are ignored.
|
||||
result = 0
|
||||
let L = parseutils.parseHex(s, result, 0)
|
||||
if L != s.len or L == 0:
|
||||
raise newException(ValueError, "invalid hex integer: " & s)
|
||||
|
|
@ -1270,9 +1278,9 @@ macro genEnumStmt(typ: typedesc, argSym: typed, default: typed): untyped =
|
|||
result = nnkCaseStmt.newTree(nnkDotExpr.newTree(argSym,
|
||||
bindSym"nimIdentNormalize"))
|
||||
# stores all processed field strings to give error msg for ambiguous enums
|
||||
var foundFields: seq[string]
|
||||
var fStr: string # string of current field
|
||||
var fNum: BiggestInt # int value of current field
|
||||
var foundFields: seq[string] = @[]
|
||||
var fStr = "" # string of current field
|
||||
var fNum = BiggestInt(0) # int value of current field
|
||||
for f in impl:
|
||||
case f.kind
|
||||
of nnkEmpty: continue # skip first node of `enumTy`
|
||||
|
|
@ -2028,6 +2036,7 @@ proc rfind*(s, sub: string, start: Natural = 0, last = -1): int {.noSideEffect,
|
|||
if sub.len == 0:
|
||||
return -1
|
||||
let last = if last == -1: s.high else: last
|
||||
result = 0
|
||||
for i in countdown(last - sub.len + 1, start):
|
||||
for j in 0..sub.len-1:
|
||||
result = i
|
||||
|
|
@ -2044,6 +2053,7 @@ proc count*(s: string, sub: char): int {.noSideEffect,
|
|||
##
|
||||
## See also:
|
||||
## * `countLines proc<#countLines,string>`_
|
||||
result = 0
|
||||
for c in s:
|
||||
if c == sub: inc result
|
||||
|
||||
|
|
@ -2054,6 +2064,7 @@ proc count*(s: string, subs: set[char]): int {.noSideEffect,
|
|||
## See also:
|
||||
## * `countLines proc<#countLines,string>`_
|
||||
doAssert card(subs) > 0
|
||||
result = 0
|
||||
for c in s:
|
||||
if c in subs: inc result
|
||||
|
||||
|
|
@ -2066,6 +2077,7 @@ proc count*(s: string, sub: string, overlapping: bool = false): int {.
|
|||
## See also:
|
||||
## * `countLines proc<#countLines,string>`_
|
||||
doAssert sub.len > 0
|
||||
result = 0
|
||||
var i = 0
|
||||
while true:
|
||||
i = s.find(sub, i)
|
||||
|
|
@ -2313,7 +2325,7 @@ proc unescape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,
|
|||
case s[i+1]:
|
||||
of 'x':
|
||||
inc i, 2
|
||||
var c: int
|
||||
var c = 0
|
||||
i += parseutils.parseHex(s, c, i, maxLen = 2)
|
||||
result.add(chr(c))
|
||||
dec i, 2
|
||||
|
|
@ -2514,7 +2526,7 @@ proc formatSize*(bytes: int64,
|
|||
xb: int64 = bytes
|
||||
fbytes: float
|
||||
lastXb: int64 = bytes
|
||||
matchedIndex: int
|
||||
matchedIndex = 0
|
||||
prefixes: array[9, string]
|
||||
if prefix == bpColloquial:
|
||||
prefixes = collPrefixes
|
||||
|
|
|
|||
|
|
@ -895,16 +895,16 @@ proc getTime*(): Time {.tags: [TimeEffect], benign.} =
|
|||
millis mod convert(Seconds, Milliseconds, 1).int)
|
||||
result = initTime(seconds, nanos)
|
||||
elif defined(macosx):
|
||||
var a: Timeval
|
||||
var a {.noinit.}: Timeval
|
||||
gettimeofday(a)
|
||||
result = initTime(a.tv_sec.int64,
|
||||
convert(Microseconds, Nanoseconds, a.tv_usec.int))
|
||||
elif defined(posix):
|
||||
var ts: Timespec
|
||||
var ts {.noinit.}: Timespec
|
||||
discard clock_gettime(CLOCK_REALTIME, ts)
|
||||
result = initTime(ts.tv_sec.int64, ts.tv_nsec.int)
|
||||
elif defined(windows):
|
||||
var f: FILETIME
|
||||
var f {.noinit.}: FILETIME
|
||||
getSystemTimeAsFileTime(f)
|
||||
result = fromWinTime(rdFileTime(f))
|
||||
|
||||
|
|
@ -1756,7 +1756,7 @@ proc formatPattern(dt: DateTime, pattern: FormatPattern, result: var string,
|
|||
proc parsePattern(input: string, pattern: FormatPattern, i: var int,
|
||||
parsed: var ParsedTime, loc: DateTimeLocale): bool =
|
||||
template takeInt(allowedWidth: Slice[int], allowSign = false): int =
|
||||
var sv: int
|
||||
var sv = 0
|
||||
var pd = parseInt(input, sv, i, allowedWidth.b, allowSign)
|
||||
if pd < allowedWidth.a:
|
||||
return false
|
||||
|
|
@ -1987,6 +1987,7 @@ proc format*(dt: DateTime, f: TimeFormat,
|
|||
let dt = initDateTime(01, mJan, 2000, 00, 00, 00, utc())
|
||||
doAssert "2000-01-01" == dt.format(f)
|
||||
assertDateTimeInitialized dt
|
||||
result = ""
|
||||
var idx = 0
|
||||
while idx <= f.patterns.high:
|
||||
case f.patterns[idx].FormatPattern
|
||||
|
|
@ -2284,7 +2285,7 @@ proc between*(startDt, endDt: DateTime): TimeInterval =
|
|||
endDate.monthday.dec
|
||||
|
||||
# Years
|
||||
result.years.inc endDate.year - startDate.year - 1
|
||||
result.years = endDate.year - startDate.year - 1
|
||||
if (startDate.month, startDate.monthday) <= (endDate.month, endDate.monthday):
|
||||
result.years.inc
|
||||
startDate.year.inc result.years
|
||||
|
|
@ -2441,6 +2442,7 @@ proc evaluateInterval(dt: DateTime, interval: TimeInterval):
|
|||
var months = interval.years * 12 + interval.months
|
||||
var curYear = dt.year
|
||||
var curMonth = dt.month
|
||||
result = default(tuple[adjDur, absDur: Duration])
|
||||
# Subtracting
|
||||
if months < 0:
|
||||
for mth in countdown(-1 * months, 1):
|
||||
|
|
@ -2562,17 +2564,17 @@ proc epochTime*(): float {.tags: [TimeEffect].} =
|
|||
##
|
||||
## ``getTime`` should generally be preferred over this proc.
|
||||
when defined(macosx):
|
||||
var a: Timeval
|
||||
var a {.noinit.}: Timeval
|
||||
gettimeofday(a)
|
||||
result = toBiggestFloat(a.tv_sec.int64) + toBiggestFloat(
|
||||
a.tv_usec)*0.00_0001
|
||||
elif defined(posix):
|
||||
var ts: Timespec
|
||||
var ts {.noinit.}: Timespec
|
||||
discard clock_gettime(CLOCK_REALTIME, ts)
|
||||
result = toBiggestFloat(ts.tv_sec.int64) +
|
||||
toBiggestFloat(ts.tv_nsec.int64) / 1_000_000_000
|
||||
elif defined(windows):
|
||||
var f: winlean.FILETIME
|
||||
var f {.noinit.}: winlean.FILETIME
|
||||
getSystemTimeAsFileTime(f)
|
||||
var i64 = rdFileTime(f) - epochDiff
|
||||
var secs = i64 div rateDiff
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ macro genericParamsImpl(T: typedesc): untyped =
|
|||
of nnkBracketExpr:
|
||||
for i in 1..<impl.len:
|
||||
let ai = impl[i]
|
||||
var ret: NimNode
|
||||
var ret: NimNode = nil
|
||||
case ai.typeKind
|
||||
of ntyTypeDesc:
|
||||
ret = ai
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ proc runeLen*(s: string): int {.rtl, extern: "nuc$1".} =
|
|||
doAssert a.runeLen == 6
|
||||
## note: a.len == 8
|
||||
|
||||
result = 0
|
||||
var i = 0
|
||||
while i < len(s):
|
||||
if uint(s[i]) <= 127: inc(i)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue