More of StringStream now works at compile time (#12284)
* readLine of StringStream now works at compile time * Work for js backend only at compile time * readAll now works at CT * readAll works in js ct now * Add test
This commit is contained in:
parent
85db42ad8c
commit
16c39f9b2e
2 changed files with 114 additions and 28 deletions
|
|
@ -251,16 +251,29 @@ when not defined(js):
|
||||||
strm.close()
|
strm.close()
|
||||||
|
|
||||||
const bufferSize = 1024
|
const bufferSize = 1024
|
||||||
var buffer {.noinit.}: array[bufferSize, char]
|
when nimvm:
|
||||||
while true:
|
var buffer2: string
|
||||||
let readBytes = readData(s, addr(buffer[0]), bufferSize)
|
buffer2.setLen(bufferSize)
|
||||||
if readBytes == 0:
|
while true:
|
||||||
break
|
let readBytes = readDataStr(s, buffer2, 0..<bufferSize)
|
||||||
let prevLen = result.len
|
if readBytes == 0:
|
||||||
result.setLen(prevLen + readBytes)
|
break
|
||||||
copyMem(addr(result[prevLen]), addr(buffer[0]), readBytes)
|
let prevLen = result.len
|
||||||
if readBytes < bufferSize:
|
result.setLen(prevLen + readBytes)
|
||||||
break
|
result[prevLen..<prevLen+readBytes] = buffer2[0..<readBytes]
|
||||||
|
if readBytes < bufferSize:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
var buffer {.noinit.}: array[bufferSize, char]
|
||||||
|
while true:
|
||||||
|
let readBytes = readData(s, addr(buffer[0]), bufferSize)
|
||||||
|
if readBytes == 0:
|
||||||
|
break
|
||||||
|
let prevLen = result.len
|
||||||
|
result.setLen(prevLen + readBytes)
|
||||||
|
copyMem(addr(result[prevLen]), addr(buffer[0]), readBytes)
|
||||||
|
if readBytes < bufferSize:
|
||||||
|
break
|
||||||
|
|
||||||
proc peekData*(s: Stream, buffer: pointer, bufLen: int): int =
|
proc peekData*(s: Stream, buffer: pointer, bufLen: int): int =
|
||||||
## Low level proc that reads data into an untyped `buffer` of `bufLen` size
|
## Low level proc that reads data into an untyped `buffer` of `bufLen` size
|
||||||
|
|
@ -399,7 +412,12 @@ proc readChar*(s: Stream): char =
|
||||||
doAssert strm.readChar() == '\x00'
|
doAssert strm.readChar() == '\x00'
|
||||||
strm.close()
|
strm.close()
|
||||||
|
|
||||||
if readData(s, addr(result), sizeof(result)) != 1: result = '\0'
|
when nimvm:
|
||||||
|
var str = " "
|
||||||
|
if readDataStr(s, str, 0..<sizeof(result)) != 1: result = '\0'
|
||||||
|
else: result = str[0]
|
||||||
|
else:
|
||||||
|
if readData(s, addr(result), sizeof(result)) != 1: result = '\0'
|
||||||
|
|
||||||
proc peekChar*(s: Stream): char =
|
proc peekChar*(s: Stream): char =
|
||||||
## Peeks a char from the stream `s`. Raises `IOError` if an error occurred.
|
## Peeks a char from the stream `s`. Raises `IOError` if an error occurred.
|
||||||
|
|
@ -884,7 +902,10 @@ proc readLine*(s: Stream, line: var TaintedString): bool =
|
||||||
result = s.readLineImpl(s, line)
|
result = s.readLineImpl(s, line)
|
||||||
else:
|
else:
|
||||||
# fallback
|
# fallback
|
||||||
line.string.setLen(0)
|
when nimvm: #Bug #12282
|
||||||
|
line.setLen(0)
|
||||||
|
else:
|
||||||
|
line.string.setLen(0)
|
||||||
while true:
|
while true:
|
||||||
var c = readChar(s)
|
var c = readChar(s)
|
||||||
if c == '\c':
|
if c == '\c':
|
||||||
|
|
@ -894,7 +915,10 @@ proc readLine*(s: Stream, line: var TaintedString): bool =
|
||||||
elif c == '\0':
|
elif c == '\0':
|
||||||
if line.len > 0: break
|
if line.len > 0: break
|
||||||
else: return false
|
else: return false
|
||||||
line.string.add(c)
|
when nimvm: #Bug #12282
|
||||||
|
line.add(c)
|
||||||
|
else:
|
||||||
|
line.string.add(c)
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc peekLine*(s: Stream, line: var TaintedString): bool =
|
proc peekLine*(s: Stream, line: var TaintedString): bool =
|
||||||
|
|
@ -999,21 +1023,73 @@ iterator lines*(s: Stream): TaintedString =
|
||||||
while s.readLine(line):
|
while s.readLine(line):
|
||||||
yield line
|
yield line
|
||||||
|
|
||||||
when not defined(js):
|
type
|
||||||
|
StringStream* = ref StringStreamObj
|
||||||
|
## A stream that encapsulates a string.
|
||||||
|
##
|
||||||
|
## **Note:** Not available for JS backend.
|
||||||
|
StringStreamObj* = object of StreamObj
|
||||||
|
## A string stream object.
|
||||||
|
##
|
||||||
|
## **Note:** Not available for JS backend.
|
||||||
|
data*: string ## A string data.
|
||||||
|
## This is updated when called `writeLine` etc.
|
||||||
|
pos: int
|
||||||
|
|
||||||
type
|
when defined(js): #This section exists so that string streams work at compile time for the js backend
|
||||||
StringStream* = ref StringStreamObj
|
proc ssAtEnd(s: Stream): bool {.compileTime.} =
|
||||||
## A stream that encapsulates a string.
|
var s = StringStream(s)
|
||||||
##
|
return s.pos >= s.data.len
|
||||||
## **Note:** Not available for JS backend.
|
|
||||||
StringStreamObj* = object of StreamObj
|
|
||||||
## A string stream object.
|
|
||||||
##
|
|
||||||
## **Note:** Not available for JS backend.
|
|
||||||
data*: string ## A string data.
|
|
||||||
## This is updated when called `writeLine` etc.
|
|
||||||
pos: int
|
|
||||||
|
|
||||||
|
proc ssSetPosition(s: Stream, pos: int) {.compileTime.} =
|
||||||
|
var s = StringStream(s)
|
||||||
|
s.pos = clamp(pos, 0, s.data.len)
|
||||||
|
|
||||||
|
proc ssGetPosition(s: Stream): int {.compileTime.} =
|
||||||
|
var s = StringStream(s)
|
||||||
|
return s.pos
|
||||||
|
|
||||||
|
proc ssReadDataStr(s: Stream, buffer: var string, slice: Slice[int]): int {.compileTime.} =
|
||||||
|
var s = StringStream(s)
|
||||||
|
result = min(slice.b + 1 - slice.a, s.data.len - s.pos)
|
||||||
|
if result > 0:
|
||||||
|
buffer[slice.a..<slice.a+result] = s.data[s.pos..<s.pos+result]
|
||||||
|
inc(s.pos, result)
|
||||||
|
else:
|
||||||
|
result = 0
|
||||||
|
|
||||||
|
proc ssClose(s: Stream) {.compileTime.} =
|
||||||
|
var s = StringStream(s)
|
||||||
|
when defined(nimNoNilSeqs):
|
||||||
|
s.data = ""
|
||||||
|
else:
|
||||||
|
s.data = nil
|
||||||
|
|
||||||
|
proc newStringStream*(s: string = ""): owned StringStream {.compileTime.} =
|
||||||
|
new(result)
|
||||||
|
result.data = s
|
||||||
|
result.pos = 0
|
||||||
|
result.closeImpl = ssClose
|
||||||
|
result.atEndImpl = ssAtEnd
|
||||||
|
result.setPositionImpl = ssSetPosition
|
||||||
|
result.getPositionImpl = ssGetPosition
|
||||||
|
result.readDataStrImpl = ssReadDataStr
|
||||||
|
|
||||||
|
proc readAll*(s: Stream): string {.compileTime.} =
|
||||||
|
const bufferSize = 1024
|
||||||
|
var bufferr: string
|
||||||
|
bufferr.setLen(bufferSize)
|
||||||
|
while true:
|
||||||
|
let readBytes = readDataStr(s, bufferr, 0..<bufferSize)
|
||||||
|
if readBytes == 0:
|
||||||
|
break
|
||||||
|
let prevLen = result.len
|
||||||
|
result.setLen(prevLen + readBytes)
|
||||||
|
result[prevLen..<prevLen+readBytes] = bufferr[0..<readBytes]
|
||||||
|
if readBytes < bufferSize:
|
||||||
|
break
|
||||||
|
|
||||||
|
else:
|
||||||
proc ssAtEnd(s: Stream): bool =
|
proc ssAtEnd(s: Stream): bool =
|
||||||
var s = StringStream(s)
|
var s = StringStream(s)
|
||||||
return s.pos >= s.data.len
|
return s.pos >= s.data.len
|
||||||
|
|
@ -1031,8 +1107,7 @@ when not defined(js):
|
||||||
result = min(slice.b + 1 - slice.a, s.data.len - s.pos)
|
result = min(slice.b + 1 - slice.a, s.data.len - s.pos)
|
||||||
if result > 0:
|
if result > 0:
|
||||||
when nimvm:
|
when nimvm:
|
||||||
for i in 0 ..< result: # sorry, but no fast string splicing on the vm.
|
buffer[slice.a..<slice.a+result] = s.data[s.pos..<s.pos+result]
|
||||||
buffer[slice.a + i] = s.data[s.pos + i]
|
|
||||||
else:
|
else:
|
||||||
copyMem(unsafeAddr buffer[slice.a], addr s.data[s.pos], result)
|
copyMem(unsafeAddr buffer[slice.a], addr s.data[s.pos], result)
|
||||||
inc(s.pos, result)
|
inc(s.pos, result)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
discard """
|
discard """
|
||||||
output: "threw exception"
|
output: "threw exception"
|
||||||
|
nimout: '''
|
||||||
|
I
|
||||||
|
AM
|
||||||
|
GROOT
|
||||||
|
'''
|
||||||
"""
|
"""
|
||||||
import streams
|
import streams
|
||||||
|
|
||||||
|
|
@ -7,3 +12,9 @@ try:
|
||||||
var fs = openFileStream("shouldneverexist.txt")
|
var fs = openFileStream("shouldneverexist.txt")
|
||||||
except IoError:
|
except IoError:
|
||||||
echo "threw exception"
|
echo "threw exception"
|
||||||
|
|
||||||
|
static:
|
||||||
|
var s = newStringStream("I\nAM\nGROOT")
|
||||||
|
for line in s.lines:
|
||||||
|
echo line
|
||||||
|
s.close
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue