101 lines
2.1 KiB
Nim
101 lines
2.1 KiB
Nim
discard """
|
|
output: '''allocating
|
|
allocating
|
|
allocating
|
|
55
|
|
60
|
|
99
|
|
deallocating
|
|
deallocating
|
|
deallocating
|
|
'''
|
|
cmd: '''nim c --newruntime $file'''
|
|
"""
|
|
|
|
type
|
|
SharedPtr*[T] = object
|
|
x: ptr T
|
|
|
|
#proc isNil[T](s: SharedPtr[T]): bool {.inline.} = s.x.isNil
|
|
|
|
template incRef(x) =
|
|
atomicInc(x.refcount)
|
|
|
|
template decRef(x): untyped = atomicDec(x.refcount)
|
|
|
|
proc makeShared*[T](x: T): SharedPtr[T] =
|
|
# XXX could benefit from 'sink' parameter.
|
|
# XXX could benefit from a macro that generates it.
|
|
result = cast[SharedPtr[T]](allocShared(sizeof(x)))
|
|
result.x[] = x
|
|
echo "allocating"
|
|
|
|
proc `=destroy`*[T](dest: var SharedPtr[T]) =
|
|
var s = dest.x
|
|
if s != nil and decRef(s) == 0:
|
|
`=destroy`(s[])
|
|
deallocShared(s)
|
|
echo "deallocating"
|
|
dest.x = nil
|
|
|
|
proc `=`*[T](dest: var SharedPtr[T]; src: SharedPtr[T]) =
|
|
var s = src.x
|
|
if s != nil: incRef(s)
|
|
#atomicSwap(dest, s)
|
|
# XXX use an atomic store here:
|
|
swap(dest.x, s)
|
|
if s != nil and decRef(s) == 0:
|
|
`=destroy`(s[])
|
|
deallocShared(s)
|
|
echo "deallocating"
|
|
|
|
proc `=sink`*[T](dest: var SharedPtr[T]; src: SharedPtr[T]) =
|
|
## XXX make this an atomic store:
|
|
if dest.x != src.x:
|
|
let s = dest.x
|
|
if s != nil:
|
|
`=destroy`(s[])
|
|
deallocShared(s)
|
|
echo "deallocating"
|
|
dest.x = src.x
|
|
|
|
template `.`*[T](s: SharedPtr[T]; field: untyped): untyped =
|
|
s.x.field
|
|
|
|
template `.=`*[T](s: SharedPtr[T]; field, value: untyped) =
|
|
s.x.field = value
|
|
|
|
from macros import unpackVarargs
|
|
|
|
template `.()`*[T](s: SharedPtr[T]; field: untyped, args: varargs[untyped]): untyped =
|
|
unpackVarargs(s.x.field, args)
|
|
|
|
|
|
type
|
|
Tree = SharedPtr[TreeObj]
|
|
TreeObj = object
|
|
refcount: int
|
|
le, ri: Tree
|
|
data: int
|
|
|
|
proc takesTree(a: Tree) =
|
|
if not a.isNil:
|
|
takesTree(a.le)
|
|
echo a.data
|
|
takesTree(a.ri)
|
|
|
|
proc createTree(data: int): Tree =
|
|
result = makeShared(TreeObj(refcount: 1, data: data))
|
|
|
|
proc createTree(data: int; le, ri: Tree): Tree =
|
|
result = makeShared(TreeObj(refcount: 1, le: le, ri: ri, data: data))
|
|
|
|
|
|
proc main =
|
|
let le = createTree(55)
|
|
let ri = createTree(99)
|
|
let t = createTree(60, le, ri)
|
|
takesTree(t)
|
|
|
|
main()
|
|
|