Skip to content

Instantly share code, notes, and snippets.

@planetis-m
Last active June 10, 2021 11:05
Show Gist options
  • Save planetis-m/9f02a1b1ae864b9d0f0a5af8c018df51 to your computer and use it in GitHub Desktop.
Save planetis-m/9f02a1b1ae864b9d0f0a5af8c018df51 to your computer and use it in GitHub Desktop.
# Compile with: nim c --gc:orc --panics:on --fieldChecks:on casevariants
# Compare with -d:emiDuplicateKey -d:emiLenient
import eminim, std/[parsejson, streams]
type
Fruit = enum
Banana, Apple
Bar = object
shared: int
case kind: Fruit
of Banana:
bad: float
banana: int
of Apple: apple: string
OnceCtx = object
shared, kind, bad, banana, apple: bool
when defined(emiNextgen):
proc transFromBanana(dst: var Bar, p: var JsonParser; kind: Fruit; o: OnceCtx) {.inline.} =
when not defined(emiLenient):
if o.bad or o.banana: raiseParseErr(p, "valid object field")
# Common fields get copied
case dst.kind
of Apple:
var tmpShared: int
if o.shared: tmpShared = move dst.shared
dst = (typeof dst)(kind: kind, shared: tmpShared)
else: discard
proc transFromApple(dst: var Bar, p: var JsonParser; kind: Fruit; o: OnceCtx) {.inline.} =
when not defined(emiLenient):
if o.apple: raiseParseErr(p, "valid object field")
case dst.kind
of Banana:
var tmpShared: int
if o.shared: tmpShared = move dst.shared
dst = (typeof dst)(kind: kind, shared: tmpShared)
else: discard
proc initFromJson(dst: var Bar, p: var JsonParser) =
var o: OnceCtx
eat(p, tkCurlyLe)
while p.tok != tkCurlyRi:
if p.tok != tkString:
raiseParseErr(p, "string literal as key")
case p.a
of "shared":
discard getTok(p)
eat(p, tkColon)
if not o.shared:
o.shared = true
initFromJson(dst.shared, p)
else:
when defined(emiDuplicateKey): skipJson(p)
else: raiseParseErr(p, "unique key")
of "kind":
discard getTok(p)
eat(p, tkColon)
var kindTmp: Fruit
if not o.kind:
o.kind = true
initFromJson(kindTmp, p)
else:
when defined(emiDuplicateKey): skipJson(p)
else: raiseParseErr(p, "unique key")
if dst.kind != kindTmp:
case dst.kind
of Banana:
transFromBanana(dst, p, kindTmp, o)
of Apple:
transFromApple(dst, p, kindTmp, o)
of "bad":
case dst.kind
of Apple:
transFromApple(dst, p, Banana, o)
else: discard
discard getTok(p)
eat(p, tkColon)
if not o.bad:
o.bad = true
initFromJson(dst.bad, p)
else:
when defined(emiDuplicateKey): skipJson(p)
else: raiseParseErr(p, "unique key")
of "banana":
case dst.kind
of Apple:
transFromApple(dst, p, Banana, o)
else: discard
discard getTok(p)
eat(p, tkColon)
if not o.banana:
o.banana = true
initFromJson(dst.banana, p)
else:
when defined(emiDuplicateKey): skipJson(p)
else: raiseParseErr(p, "unique key")
of "apple":
case dst.kind
of Banana:
transFromApple(dst, p, Apple, o)
else: discard
discard getTok(p)
eat(p, tkColon)
if not o.apple:
o.apple = true
initFromJson(dst.apple, p)
else:
when defined(emiDuplicateKey): skipJson(p)
else: raiseParseErr(p, "unique key")
else:
when defined(emiLenient): skipJson(p)
else: raiseParseErr(p, "valid object field")
if p.tok != tkComma:
break
discard getTok(p)
eat(p, tkCurlyRi)
#[
let data =
#"""[{"shared":1,"kind":"Apple","apple":"world"},{"bad":1.0,"kind":"Banana","shared":2}]"""
# Invalid
#"""[{"shared":1,"apple":"world","kind":"Banana"}]"""
#"""[{"shared":1,"kind":"Apple","apple":"world","kind":"Banana"}]"""
# Bug with -d:emiLenient!
"""[{"shared":1,"banana":2,"apple":"world","kind":"Banana"}]"""
let s = newStringStream(data)
echo s.jsonTo(seq[Bar])
]#
import std / [times, stats, strformat,random]
const MaxIter = 1_000_000
proc warmup() =
# Warmup - make sure cpu is on max perf
let start = cpuTime()
var a = 123
for i in 0 ..< 300_000_000:
a += i * i mod 456
a = a mod 789
let dur = cpuTime() - start
echo &"Warmup: {dur:>4.4f} s ", a
proc printStats(name: string, stats: RunningStat, dur: float) =
echo &"""{name}:
Collected {stats.n} samples in {dur:>4.4f} s
Average time: {stats.mean * 1000:>4.4f} ms
Stddev time: {stats.standardDeviationS * 1000:>4.4f} ms
Min time: {stats.min * 1000:>4.4f} ms
Max time: {stats.max * 1000:>4.4f} ms"""
template bench(name, samples, code: untyped) =
var stats: RunningStat
let globalStart = cpuTime()
for i in 0 ..< samples:
let start = cpuTime()
code
let duration = cpuTime() - start
stats.push duration
let globalDuration = cpuTime() - globalStart
printStats(name, stats, globalDuration)
proc main =
randomize()
warmup()
var s = newStringStream(newStringOfCap(50*MaxIter))
var data: seq[Bar]
for i in 0..<MaxIter:
data.add Bar(kind: if rand(1.0) <= 0.5: Banana else: Apple)
s.storeJson(data)
s.setPosition(0)
var
a: seq[Bar]
bench("emi", 1):
a = s.jsonTo(typeof data)
echo a[0..4]
main()
@planetis-m
Copy link
Author

planetis-m commented Jun 10, 2021

Results on my machine:

-d:emiNextgen: 620.3714 ms
without: 726.8404 ms

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment