-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy patharc.nim
58 lines (45 loc) · 1.67 KB
/
arc.nim
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
#[
Some types and constants copied from stdlib so we can mimic rc against the
standard ref header.
]#
when defined(gcOrc):
const
rcIncrement = 0b10000 # so that lowest 4 bits are not touched
rcMask = 0b1111
rcShift = 4 # shift by rcShift to get the reference counter
else:
const
rcIncrement = 0b1000 # so that lowest 3 bits are not touched
rcMask = 0b111
rcShift = 3 # shift by rcShift to get the reference counter
template shit(n: int): int = n shl rcShift
template unshit(n: int): int = n shr rcShift
type
RefHeader = object
rc: int
when defined(gcOrc):
rootIdx: int
when defined(nimArcDebug) or defined(nimArcIds):
refId: int
Cell = ptr RefHeader
template head(p: ref): Cell =
cast[Cell](cast[int](p) -% sizeof(RefHeader))
template rcPtr(p: ref): ptr int = addr head(p)[].rc
proc atomicRC*(p: ref, order: AtomMemModel = ATOMIC_SEQ_CST): int =
## returns the current rc
atomicLoad(rcPtr(p), addr result, order)
result = unshit result
proc atomicRC*(p: ref; n: int, order: AtomMemModel = ATOMIC_SEQ_CST) =
## sets the rc to the provided value
let old = atomicFetchAnd(rcPtr(p), rcMask, order)
let n = (shit n) and old
atomicStore(rcPtr(p), unsafeAddr n, order)
proc atomicIncRef*(p: ref, order: AtomMemModel = ATOMIC_SEQ_CST): int =
## returns the old value
unshit atomicFetchAdd(rcPtr(p), rcIncrement, order)
proc atomicDecRef*(p: ref, order: AtomMemModel = ATOMIC_SEQ_CST): int =
## returns the old value
unshit atomicFetchSub(rcPtr(p), rcIncrement, order)
template isIsolated*(p: ref, order: AtomMemModel = ATOMIC_SEQ_CST): bool =
## true if the ref is the sole owner
atomicRC(p) == 0