Skip to content

Instantly share code, notes, and snippets.

@bogen
Created August 8, 2014 06:23
Show Gist options
  • Save bogen/e41e2ca5e197279659bc to your computer and use it in GitHub Desktop.
Save bogen/e41e2ca5e197279659bc to your computer and use it in GitHub Desktop.
echo that will handle embedded nuls
See https://github.com/Araq/Nimrod/issues/1137 (nimecho0 and nimecho1 echo strings with embedded nuls)
$ nimrod c -x:off --opt:speed --deadCodeElim:on --stackTrace:off --lineTrace:off nimecho.nim
$ ./nimecho 0 > /dev/null
using nimecho0
1.8825269999999998e+00 seconds elapsed
1.8825269999999999e-06 seconds per iteration
string used: some very long string some very long string some very long string some very long string some very long string some very long string
$ ./nimecho 1 > /dev/null
using nimecho1 (smallest code)
2.2058490000000002e+00 seconds elapsed
2.2058490000000000e-06 seconds per iteration
string used: some very long string some very long string some very long string some very long string some very long string some very long string
$ ./nimecho e > /dev/null
using original echo
9.7179199999999999e-01 seconds elapsed
9.7179199999999994e-07 seconds per iteration
string used: some very long string some very long string some very long string some very long string some very long string some very long string
$ ./nimecho 3
some very long string some very long string some very long string some very long string some very long string some very long string 1235.5999999999999996e+00
some very long string some very long string some very long string some very long string some very long string some very long string 1235.5999999999999996e+00
some very long string some very long string some very long string some very long string some very long string some very long string 1235.5999999999999996e+00
nulltest
nulltest
-----------------------------------------
My vote is for nimecho1 even though it is the slowest, because it is simplest code
import os, strutils, times
let argv = commandLineParams()
proc nimecho0 (a: varargs[string, `$`]) {.compilerProc.} =
# declare external c functions. Use ints for pointers to avoid casting
proc c_fwrite (buf: int, size, n: int, f: TFile) {.importc: "fwrite", noDecl.}
proc c_memcpy (a: int, b: cstring, size: int) {.importc: "memcpy", noDecl.}
proc c_alloca (n: int): int {.importc: "alloca", noDecl.}
var size : int = 1 # reserve space for trailing newline
for i in 0..a.len-1: size += a [i].len # add sum of string lengths
let dst0 = c_alloca (size) # allocate output buffer on the stack
var dst = dst0 # point to the start of the buffer
for i in 0..a.len-1: # for all strings to be displayed
c_memcpy (dst, a [i], a [i].len) # append string to the output buffer
dst += a [i].len # advance to the end of the buffer
c_memcpy (dst, "\n", 1) # append the trailing newline
c_fwrite (dst0, size, 1, stdout) # write the buffer to standard out
proc nimecho1 (a: varargs[string, `$`]) =
# join strings and append new line
let buffer = join (a) & "\n";
# write the buffer to standard out
discard writeBuffer (stdout, cstring (buffer), buffer.len);
proc test () =
const testString = "some very long string some very long string some very long string some very long string some very long string some very long string "
proc usenimecho1 () = nimecho1 testString, 1, 2, 3, 5.6
proc useorigecho () = echo testString, 1, 2, 3, 5.6
proc usenimecho0 () = nimecho0 testString, 1, 2, 3, 5.6
var testecho = usenimecho1
if argv.len > 0:
if argv [0][0] == 'e':
writeln stderr, "using original echo"
testecho = useorigecho
if argv [0][0] == '0':
writeln stderr, "using nimecho0"
testecho = usenimecho0
if argv [0][0] == '1':
writeln stderr, "using nimecho1 (smallest code)"
testecho = usenimecho1
if argv [0][0] == '3':
useorigecho ()
usenimecho1 ()
usenimecho0 ()
nimecho0 ()
nimecho1 ()
nimecho0 ("null\0test")
nimecho1 ("null\0test")
return
const loops = 1_000_000
let start = cpuTime ()
for i in 1..loops: testecho ()
let finish = cpuTime ()
let elapsed = finish-start
writeln stderr, elapsed, " seconds elapsed"
writeln stderr, elapsed/float (loops), " seconds per iteration"
writeln stderr, "string used: ", testString
test ()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment