Turn the consumeOutputs templates into procs to reduce code bloat

This commit is contained in:
Zahary Karadjov 2020-11-27 19:31:07 +02:00
commit 65f82f2f2d
No known key found for this signature in database
GPG key ID: C8936F8A3073D609

View file

@ -249,17 +249,20 @@ template vtableAddr*(vtable: OutputStreamVTable): ptr OutputStreamVTable =
{.noSideEffect.}: {.noSideEffect.}:
unsafeAddr vtable unsafeAddr vtable
proc fileOutput*(filename: string, proc fileOutput*(f: File,
fileMode: FileMode = fmWrite,
pageSize = defaultPageSize): OutputStreamHandle pageSize = defaultPageSize): OutputStreamHandle
{.raises: [IOError, Defect].} = {.raises: [IOError, Defect].} =
let f = open(filename, fileMode)
makeHandle FileOutputStream( makeHandle FileOutputStream(
vtable: vtableAddr fileOutputVTable, vtable: vtableAddr fileOutputVTable,
buffers: initPageBuffers(pageSize), buffers: initPageBuffers(pageSize),
file: f) file: f)
proc fileOutput*(filename: string,
fileMode: FileMode = fmWrite,
pageSize = defaultPageSize): OutputStreamHandle
{.raises: [IOError, Defect].} =
fileOutput(open(filename, fileMode), pageSize)
proc pos*(s: OutputStream): int = proc pos*(s: OutputStream): int =
s.spanEndPos - s.span.len s.spanEndPos - s.span.len
@ -690,35 +693,36 @@ proc writeMemCopy*[T](c: var WriteCursor, value: T) =
proc write*(c: var WriteCursor, str: string) = proc write*(c: var WriteCursor, str: string) =
writeBytesToCursor(c, str.toOpenArrayByte(0, str.len - 1)) writeBytesToCursor(c, str.toOpenArrayByte(0, str.len - 1))
template consumeOutputs*(sp: OutputStream, bytesVar, body: untyped) = type
OutputConsumingProc = proc (data: openArray[byte])
{.gcsafe, raises: [Defect].}
proc consumeOutputsImpl(s: OutputStream, consumer: OutputConsumingProc) =
let runway = s.span.len
fsAssert s.extCursorsCount == 0 and s.buffers != nil
trackWrittenTo(s.buffers, s.span.startAddr)
for pageReadableStart, pageLen in consumePageBuffers(s.buffers):
consumer(makeOpenArray(pageReadableStart, pageLen))
s.span = getWritableSpan(s.buffers)
s.spanEndPos += s.span.len - runway
template consumeOutputs*(s: OutputStream, bytesVar, body: untyped) =
## Please note that calling `consumeOutputs` on an unbuffered stream ## Please note that calling `consumeOutputs` on an unbuffered stream
## or an unsafe memory stream is considered a Defect. ## or an unsafe memory stream is considered a Defect.
## ##
## Before consuming the outputs, all outstanding delayed writes must ## Before consuming the outputs, all outstanding delayed writes must
## be finalized. ## be finalized.
let s = sp proc consumer(bytesVar: openarray[byte]) {.gcsafe, raises: [Defect].} =
fsAssert s.extCursorsCount == 0 and s.buffers != nil
for pageReadableStart, pageLen in consumePageBuffers(s.buffers):
template bytesVar: untyped =
makeOpenArray(pageReadableStart, pageLen)
body body
template consumeContiguousOutput*(sp: OutputStream, bytesVar, body: untyped) = consumeOutputsImpl(s, consumer)
## Please note that calling `consumeContiguousOutput` on an unbuffered stream
## or an unsafe memory stream is considered a Defect.
##
## Before consuming the output, all outstanding delayed writes must
## be finalized.
##
# TODO: This code is a bit too much to be inlined. Maybe this should be proc consumeContiguousOutputImpl(s: OutputStream, consumer: OutputConsumingProc) =
# a proc with a callback, but this will restrict the types of variables
# it can write to. OTOH, perhaps only `consumePageBuffers` is the offending
# part.
var var
s = sp runway = s.span.len
contigiousBytes: string contigiousBytes: string
# this may remain null # this may remain null
# We are using a string, because `newStringOfCap` doesn't zero out # We are using a string, because `newStringOfCap` doesn't zero out
@ -727,6 +731,7 @@ template consumeContiguousOutput*(sp: OutputStream, bytesVar, body: untyped) =
bytesLen: int bytesLen: int
fsAssert s.extCursorsCount == 0 and s.buffers != nil fsAssert s.extCursorsCount == 0 and s.buffers != nil
s.buffers.trackWrittenTo s.span.startAddr
if s.buffers.queue.len == 1: if s.buffers.queue.len == 1:
let page = s.buffers.queue[0] let page = s.buffers.queue[0]
@ -736,18 +741,30 @@ template consumeContiguousOutput*(sp: OutputStream, bytesVar, body: untyped) =
page.consumedTo = 0 page.consumedTo = 0
page.writtenTo = 0 page.writtenTo = 0
else: else:
contigiousBytes = newStringOfCap(s.pos) contigiousBytes = newStringOfCap(s.buffers.totalBufferedBytes)
for pageReadableStart, pageLen in consumePageBuffers(s.buffers): for pageReadableStart, pageLen in consumePageBuffers(s.buffers):
contigiousBytes.add makeOpenArray(cast[ptr char](pageReadableStart), pageLen) contigiousBytes.add makeOpenArray(cast[ptr char](pageReadableStart), pageLen)
bytesPtr = addr contigiousBytes[0] bytesPtr = cast[ptr byte](addr contigiousBytes[0])
bytesLen = contigiousBytes.len bytesLen = contigiousBytes.len
template bytesVar: untyped = consumer(makeOpenArray(bytesPtr, bytesLen))
makeOpenArray(bytesPtr, bytesLen)
body s.span = s.buffers.getWritableSpan()
s.spanEndPos += s.span.len - runway
template consumeContiguousOutput*(s: OutputStream, bytesVar, body: untyped) =
## Please note that calling `consumeContiguousOutput` on an unbuffered stream
## or an unsafe memory stream is considered a Defect.
##
## Before consuming the output, all outstanding delayed writes must
## be finalized.
##
proc consumer(bytesVar: openarray[byte]) {.gcsafe, raises: [Defect].} =
body
consumeContiguousOutputImpl(s, consumer)
proc getOutput*(s: OutputStream, T: type string): string = proc getOutput*(s: OutputStream, T: type string): string =
## Please note that calling `getOutput` on an unbuffered stream ## Please note that calling `getOutput` on an unbuffered stream