Speed up readLine by using getc_unlocked
- Only on POSIX and Windows (_fgetc_nolock here) systems - File is locked to our thread before and unlocked after readLine - About 3 times faster in some simple tests
This commit is contained in:
parent
c707923cc1
commit
ef9a3b4d3b
1 changed files with 52 additions and 16 deletions
|
|
@ -31,6 +31,24 @@ proc fprintf(f: File, frmt: cstring) {.importc: "fprintf",
|
||||||
proc strlen(c: cstring): int {.
|
proc strlen(c: cstring): int {.
|
||||||
importc: "strlen", header: "<string.h>", tags: [].}
|
importc: "strlen", header: "<string.h>", tags: [].}
|
||||||
|
|
||||||
|
when defined(posix):
|
||||||
|
proc getc_unlocked(stream: File): cint {.importc: "getc_unlocked",
|
||||||
|
header: "<stdio.h>", tags: [ReadIOEffect].}
|
||||||
|
|
||||||
|
proc flockfile(stream: File) {.importc: "flockfile", header: "<stdio.h>",
|
||||||
|
tags: [ReadIOEffect].}
|
||||||
|
|
||||||
|
proc funlockfile(stream: File) {.importc: "funlockfile", header: "<stdio.h>",
|
||||||
|
tags: [ReadIOEffect].}
|
||||||
|
elif defined(windows):
|
||||||
|
proc getc_unlocked(stream: File): cint {.importc: "_fgetc_nolock",
|
||||||
|
header: "<stdio.h>", tags: [ReadIOEffect].}
|
||||||
|
|
||||||
|
proc flockfile(stream: File) {.importc: "_lock_file", header: "<stdio.h>",
|
||||||
|
tags: [ReadIOEffect].}
|
||||||
|
|
||||||
|
proc funlockfile(stream: File) {.importc: "_unlock_file", header: "<stdio.h>",
|
||||||
|
tags: [ReadIOEffect].}
|
||||||
|
|
||||||
# C routine that is used here:
|
# C routine that is used here:
|
||||||
proc fread(buf: pointer, size, n: int, f: File): int {.
|
proc fread(buf: pointer, size, n: int, f: File): int {.
|
||||||
|
|
@ -67,22 +85,40 @@ const
|
||||||
proc raiseEIO(msg: string) {.noinline, noreturn.} =
|
proc raiseEIO(msg: string) {.noinline, noreturn.} =
|
||||||
sysFatal(IOError, msg)
|
sysFatal(IOError, msg)
|
||||||
|
|
||||||
proc readLine(f: File, line: var TaintedString): bool =
|
when defined(posix) or defined(windows):
|
||||||
# of course this could be optimized a bit; but IO is slow anyway...
|
proc readLine(f: File, line: var TaintedString): bool =
|
||||||
# and it was difficult to get this CORRECT with Ansi C's methods
|
setLen(line.string, 0) # reuse the buffer!
|
||||||
setLen(line.string, 0) # reuse the buffer!
|
flockfile(f)
|
||||||
while true:
|
while true:
|
||||||
var c = fgetc(f)
|
var c = getc_unlocked(f)
|
||||||
if c < 0'i32:
|
if c < 0'i32:
|
||||||
if line.len > 0: break
|
if line.len > 0: break
|
||||||
else: return false
|
else: return false
|
||||||
if c == 10'i32: break # LF
|
if c == 10'i32: break # LF
|
||||||
if c == 13'i32: # CR
|
if c == 13'i32: # CR
|
||||||
c = fgetc(f) # is the next char LF?
|
c = getc_unlocked(f) # is the next char LF?
|
||||||
if c != 10'i32: ungetc(c, f) # no, put the character back
|
if c != 10'i32: ungetc(c, f) # no, put the character back
|
||||||
break
|
break
|
||||||
add line.string, chr(int(c))
|
add line.string, chr(int(c))
|
||||||
result = true
|
result = true
|
||||||
|
funlockfile(f)
|
||||||
|
else:
|
||||||
|
proc readLine(f: File, line: var TaintedString): bool =
|
||||||
|
# of course this could be optimized a bit; but IO is slow anyway...
|
||||||
|
# and it was difficult to get this CORRECT with Ansi C's methods
|
||||||
|
setLen(line.string, 0) # reuse the buffer!
|
||||||
|
while true:
|
||||||
|
var c = fgetc(f)
|
||||||
|
if c < 0'i32:
|
||||||
|
if line.len > 0: break
|
||||||
|
else: return false
|
||||||
|
if c == 10'i32: break # LF
|
||||||
|
if c == 13'i32: # CR
|
||||||
|
c = fgetc(f) # is the next char LF?
|
||||||
|
if c != 10'i32: ungetc(c, f) # no, put the character back
|
||||||
|
break
|
||||||
|
add line.string, chr(int(c))
|
||||||
|
result = true
|
||||||
|
|
||||||
proc readLine(f: File): TaintedString =
|
proc readLine(f: File): TaintedString =
|
||||||
result = TaintedString(newStringOfCap(80))
|
result = TaintedString(newStringOfCap(80))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue