From caf30e7cb56c274492667892b478babe98c81647 Mon Sep 17 00:00:00 2001 From: Christopher Dunn Date: Sat, 25 Apr 2020 13:19:11 -0500 Subject: [PATCH] Faster readStr() (#14099) * Faster readStr() * https://github.com/nim-lang/Nim/issues/13857 * Add .since annotation and add to changelog * Private, un-sinced proc for csource bootstrapping --- changelog.md | 3 +++ lib/pure/streams.nim | 28 ++++++++++++++++++++++------ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/changelog.md b/changelog.md index ee584e6115..73a6ffe24b 100644 --- a/changelog.md +++ b/changelog.md @@ -37,6 +37,9 @@ and this can now throw in edge cases where `getCurrentDir` throws. `relativePath` also now works for js with `-d:nodejs`. +- Added `streams.readStr` and `streams.peekStr` overloads to + accept an existing string to modify, which avoids memory + allocations, similar to `streams.readLine` (#13857). ## Language changes - In newruntime it is now allowed to assign discriminator field without restrictions as long as case object doesn't have custom destructor. Discriminator value doesn't have to be a constant either. If you have custom destructor for case object and you do want to freely assign discriminator fields, it is recommended to refactor object into 2 objects like this: diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index cdb8819600..4af4ae2ecd 100644 --- a/lib/pure/streams.nim +++ b/lib/pure/streams.nim @@ -841,6 +841,16 @@ proc peekFloat64*(s: Stream): float64 = peek(s, result) +proc readStrPrivate(s: Stream, length: int, str: var TaintedString) = + if length > len(str): setLen(str.string, length) + var L = readData(s, cstring(str), length) + if L != len(str): setLen(str.string, L) + +proc readStr*(s: Stream, length: int, str: var TaintedString) {.since: (1, 3).} = + ## Reads a string of length `length` from the stream `s`. Raises `IOError` if + ## an error occurred. + readStrPrivate(s, length, str) + proc readStr*(s: Stream, length: int): TaintedString = ## Reads a string of length `length` from the stream `s`. Raises `IOError` if ## an error occurred. @@ -851,10 +861,18 @@ proc readStr*(s: Stream, length: int): TaintedString = doAssert strm.readStr(2) == "e" doAssert strm.readStr(2) == "" strm.close() - result = newString(length).TaintedString - var L = readData(s, cstring(result), length) - if L != length: setLen(result.string, L) + readStrPrivate(s, length, result) + +proc peekStrPrivate(s: Stream, length: int, str: var TaintedString) = + if length > len(str): setLen(str.string, length) + var L = peekData(s, cstring(str), length) + if L != len(str): setLen(str.string, L) + +proc peekStr*(s: Stream, length: int, str: var TaintedString) {.since: (1, 3).} = + ## Peeks a string of length `length` from the stream `s`. Raises `IOError` if + ## an error occurred. + peekStrPrivate(s, length, str) proc peekStr*(s: Stream, length: int): TaintedString = ## Peeks a string of length `length` from the stream `s`. Raises `IOError` if @@ -867,10 +885,8 @@ proc peekStr*(s: Stream, length: int): TaintedString = doAssert strm.readStr(2) == "ab" doAssert strm.peekStr(2) == "cd" strm.close() - result = newString(length).TaintedString - var L = peekData(s, cstring(result), length) - if L != length: setLen(result.string, L) + peekStrPrivate(s, length, result) proc readLine*(s: Stream, line: var TaintedString): bool = ## Reads a line of text from the stream `s` into `line`. `line` must not be