summary refs log tree commit diff stats
path: root/tests/destructor/tatomicptrs.nim
blob: d20596415c338ae3945ea7682e08b6d440eb8503 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
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()