Skip to content

Commit

Permalink
0.0.5: try to raise
Browse files Browse the repository at this point in the history
  • Loading branch information
disruptek committed Jun 3, 2020
1 parent 007326f commit c36da34
Show file tree
Hide file tree
Showing 6 changed files with 267 additions and 156 deletions.
2 changes: 1 addition & 1 deletion docs/frosty.html
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ <h1><a class="toc-backref" href="#12">Procs</a></h1>
<div class="twelve-columns footer">
<span class="nim-sprite"></span>
<br/>
<small style="color: var(--hint);">Made with Nim. Generated: 2020-06-02 03:41:39 UTC</small>
<small style="color: var(--hint);">Made with Nim. Generated: 2020-06-03 03:48:03 UTC</small>
</div>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion docs/theindex.html
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ <h1 class="title">Index</h1>
<div class="twelve-columns footer">
<span class="nim-sprite"></span>
<br/>
<small style="color: var(--hint);">Made with Nim. Generated: 2020-06-02 03:41:39 UTC</small>
<small style="color: var(--hint);">Made with Nim. Generated: 2020-06-03 03:48:03 UTC</small>
</div>
</div>
</div>
Expand Down
110 changes: 71 additions & 39 deletions frosty.nim
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import std/strutils
import std/streams
import std/tables

# we'll only check hashes during debug builds
when not defined(release):
import std/strutils
import std/hashes

const
Expand All @@ -22,7 +22,7 @@ type
when not defined(release):
indent: int

Chunk = object
Cube = object
p: int
when not defined(release):
h: Hash
Expand All @@ -36,9 +36,9 @@ template refAddr(o: typed): int =
proc newSerializer(stream: Stream): Serializer {.raises: [].} =
result = Serializer(stream: stream)

proc write[T](s: var Serializer; o: ref T)
proc write[T](s: var Serializer; o: ref T; parent = 0)
proc read[T](s: var Serializer; o: var ref T)
proc write[T](s: var Serializer; o: T)
proc write[T](s: var Serializer; o: T; parent = 0)
proc read[T](s: var Serializer; o: var T)
proc write[T](s: var Serializer; o: seq[T])
proc read[T](s: var Serializer; o: var seq[T])
Expand Down Expand Up @@ -86,35 +86,64 @@ template greatenIndent(s: var Serializer; body: untyped): untyped =
## Used for debugging.
when not defined(release):
s.indent = s.indent + 2
defer:
s.indent = s.indent - 2
body
when not defined(release):
s.indent = s.indent - 2

template debung(s: Serializer; msg: string): untyped =
## Used for debugging.
when defined(debug):
when not defined(release):
when not defined(release):
when not defined(nimdoc):
echo spaces(s.indent) & msg

template writeComplex(s: var Serializer; o: object | tuple) =
for k, val in fieldPairs(o):
s.write val
when not defined(nimdoc):
export greatenIndent, debung

template readComplex[T: object | tuple](s: var Serializer; o: var T) =
for k, v in fieldPairs(o):
s.read v
template writeComplex(s: var Serializer; o: object | tuple; parent = 0) =
#s.debung $typeof(o)
s.greatenIndent:
for k, val in fieldPairs(o):
when val is ref:
s.write val, parent = parent
else:
s.write val
#let q = repr(val)
#s.debung k & ": " & $typeof(val) & " = " & q[low(q)..min(20, high(q))]

when not defined(release):
template audit(o: typed; p: typed): Hash =
when defined(release):
0
else:
when compiles(hash(o)):
hash(o)
elif compiles(hash(o[])):
hash(o[])
template readComplex[T: object | tuple](s: var Serializer; o: var T) =
#s.debung $typeof(o)
s.greatenIndent:
for k, val in fieldPairs(o):
{.push fieldChecks: off.}
# work around variant objects?
var x = val
s.read x
val = x
#let q = repr(val)
#s.debung k & ": " & $typeof(val) & " = " & q[low(q)..min(20, high(q))]
{.pop.}

template audit(o: typed; g: typed) =
when defined(release):
discard
else:
# if it's a pointer,
if g.p != 0:
# compute a hash
let h =
when compiles(hash(o)):
hash(o)
elif compiles(hash(o[])):
hash(o[])
else:
hash(g.p)
# if we read a hash,
if g.h != 0:
# check it,
assert g.h == h
else:
hash(p)
# else, save it
g.h = h

proc write(s: var Serializer; o: string) =
write(s.stream, len(o)) # put the str len
Expand All @@ -124,17 +153,16 @@ proc read(s: var Serializer; o: var string) =
var l = len(o) # type inference
read(s.stream, l) # get the str len
o = readStr(s.stream, l) # get the str data
assert o.len == l
when not defined(release):
if len(o) != l:
raise newException(ValueError,
"expected string of len " & $l & " and got len " & $len(o))

proc write[T](s: var Serializer; o: ref T) =
proc write[T](s: var Serializer; o: ref T; parent = 0) =
# compute p and store it
var g = Chunk(p: refAddr(o))
#s.debung $typeof(o) & " " & $g.p
var g = Cube(p: refAddr(o))
# if it's nonzero, also compute hash
if g.p != 0:
when not defined(release):
g.h = audit(o, g.p)
assert g.h != 0
audit(o, g)

# write the preamble
s.write g
Expand All @@ -144,11 +172,14 @@ proc write[T](s: var Serializer; o: ref T) =
# so record that this memory was seen,
s.ptrs[g.p] = cast[pointer](o)
# and write it now
s.write o[]
if g.p != parent:
s.write o[], parent = g.p
else:
raise

proc read[T](s: var Serializer; o: var ref T) =
var
g: Chunk
g: Cube
s.read g
if g.p == 0:
o = nil
Expand All @@ -159,8 +190,8 @@ proc read[T](s: var Serializer; o: var ref T) =
o = new (ref T)
s.ptrs[g.p] = cast[pointer](o)
s.read o[]
when not defined(release):
assert g.h == audit(o, g.p)
# after you read it, check the hash
audit(o, g)

proc write[T](s: var Serializer; o: seq[T]) =
runnableExamples:
Expand Down Expand Up @@ -191,11 +222,11 @@ proc read[T](s: var Serializer; o: var seq[T]) =
s.read item # read into the item

# simple types are, uh, simple
proc write[T](s: var Serializer; o: T) =
proc write[T](s: var Serializer; o: T; parent = 0) =
when T is object:
writeComplex(s, o)
writeComplex(s, o, parent = parent)
elif T is tuple:
writeComplex(s, o)
writeComplex(s, o, parent = parent)
else:
write(s.stream, o)

Expand Down Expand Up @@ -254,6 +285,7 @@ proc freeze*[T](o: T): string =
var u = thaw[Uri](s)
# confirm that two objects match
assert u == q

freeze(o, result)

proc thaw*[T](stream: Stream; o: var T) =
Expand Down
29 changes: 18 additions & 11 deletions frosty.nimble
Original file line number Diff line number Diff line change
@@ -1,24 +1,31 @@
version = "0.0.4"
version = "0.0.5"
author = "disruptek"
description = "marshal native Nim objects via streams, channels"
license = "MIT"

requires "nim >= 1.0.0 & < 2.0.0"
requires "https://github.com/disruptek/criterion"
#requires "https://github.com/disruptek/criterion"

proc execCmd(cmd: string) =
echo "execCmd:" & cmd
echo "exec: " & cmd
exec cmd

proc execTest(test: string) =
execCmd "nim c -r " & test
execCmd "nim c -d:danger -r " & test
execCmd "nim cpp -r " & test
execCmd "nim cpp -d:danger -r " & test
when true:
execCmd "nim c -d:danger -r " & test & " write"
execCmd "nim c -d:danger -r " & test & " read"
execCmd "nim c -d:danger -r " & test & " write 500"
execCmd "nim c -d:danger -r " & test & " read 500"
else:
execCmd "nim c -r " & test & " write"
execCmd "nim c -d:danger -r " & test & " read"
execCmd "nim cpp -r " & test & " write"
execCmd "nim cpp -d:danger -r " & test & " read"
when NimMajor >= 1 and NimMinor >= 1:
execCmd "nim c --useVersion:1.0 -d:danger -r " & test
execCmd "nim c --gc:arc --exceptions:goto -r " & test
execCmd "nim cpp --gc:arc --exceptions:goto -r " & test
execCmd "nim c --useVersion:1.0 -d:danger -r " & test & " write"
execCmd "nim c --useVersion:1.0 -d:danger -r " & test & " read"
execCmd "nim c --gc:arc -r " & test & " write"
execCmd "nim cpp --gc:arc -r " & test & " read"

task test, "run tests for travis":
execTest("frosty.nim")
execTest("tests/test.nim")
97 changes: 97 additions & 0 deletions tests/bench.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import std/hashes
import std/times
import std/strutils
import std/streams
import std/lists
import std/intsets
import std/tables
import std/os
import std/random
import std/json
import std/uri

import criterion

import frosty

const
fn = "goats"
let
mode = if paramCount() < 1: "write" else: paramStr(1)
count = if paramCount() < 2: 1 else: parseInt paramStr(2)
echo "benching against " & $count & " units in " & fn

let
tJs = %* {
"goats": ["pigs", "horses"],
"sheep": 11,
"ducks": 12.0,
"dogs": "woof",
"cats": false,
"frogs": { "toads": true, "rats": "yep" },
}

template writeSomething*(ss: Stream; w: typed): untyped =
ss.setPosition 0
if count == 1:
freeze(w, ss)
else:
for i in 1 .. count:
freeze(w, ss)

template readSomething*(ss: Stream; w: typed): untyped =
var
r: typeof(w)
ss.setPosition 0
if count == 1:
thaw(ss, r)
else:
for i in 1 .. count:
thaw(ss, r)
r

const
tSeq = @[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
tString = "https://irclogs.nim-lang.org/01-06-2020.html#20:54:23"
tObj = parseUri(tString)
var
tIntset = initIntSet()
for i in 0 .. 10:
tIntset.incl i

var cfg = newDefaultConfig()
cfg.budget = 0.5

benchmark cfg:
var
ss = newStringStream()

proc write_seq() {.measure.} =
ss.writeSomething tSeq

proc read_seq() {.measure.} =
discard ss.readSomething tSeq

proc write_string() {.measure.} =
ss.writeSomething tString

proc read_string() {.measure.} =
discard ss.readSomething tString

proc write_obj() {.measure.} =
ss.writeSomething tObj

proc read_obj() {.measure.} =
discard ss.readSomething tObj

proc write_intset() {.measure.} =
ss.writeSomething tIntset

proc read_intset() {.measure.} =
let r = ss.readSomething tIntset

proc write_json() {.measure.} =
ss.writeSomething tJs

proc read_json() {.measure.} =
let r = ss.readSomething tJs
Loading

0 comments on commit c36da34

Please sign in to comment.