summary refs log tree commit diff stats
path: root/tests/destructor/tatomicptrs.nim
blob: d043195c9d6ec278a9b242e6de1d6af66dc592da (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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
discard """
  output: '''allocating
allocating
allocating
55
60
99
deallocating
deallocating
deallocating
allocating
deallocating
'''
joinable: false
"""

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: sink T): SharedPtr[T] =
  # 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

proc get*[T](s: SharedPtr[T]): lent T =
  s.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()



#-------------------------------------------------------
#bug #9781

type
  MySeq* [T] = object
    refcount: int
    len: int
    data: ptr UncheckedArray[T]

proc `=destroy`*[T](m: var MySeq[T]) {.inline.} =
  if m.data != nil:
    deallocShared(m.data)
    m.data = nil

proc `=`*[T](m: var MySeq[T], m2: MySeq[T]) =
  if m.data == m2.data: return
  if m.data != nil:
    `=destroy`(m)

  m.len = m2.len
  let bytes = m.len.int * sizeof(float)
  if bytes > 0:
    m.data = cast[ptr UncheckedArray[T]](allocShared(bytes))
    copyMem(m.data, m2.data, bytes)

proc `=sink`*[T](m: var MySeq[T], m2: MySeq[T]) {.inline.} =
  if m.data != m2.data:
    if m.data != nil:
      `=destroy`(m)
    m.len = m2.len
    m.data = m2.data

proc len*[T](m: MySeq[T]): int {.inline.} = m.len

proc newMySeq*[T](size: int, initial_value: T): MySeq[T] =
  result.len = size
  if size > 0:
    result.data = cast[ptr UncheckedArray[T]](allocShared(sizeof(T) * size))


let x = makeShared(newMySeq(10, 1.0))
doAssert: x.get().len == 10