summary refs log tree commit diff stats
path: root/tests/destructor/smart_ptr.nim
diff options
context:
space:
mode:
Diffstat (limited to 'tests/destructor/smart_ptr.nim')
-rw-r--r--tests/destructor/smart_ptr.nim49
1 files changed, 49 insertions, 0 deletions
diff --git a/tests/destructor/smart_ptr.nim b/tests/destructor/smart_ptr.nim
new file mode 100644
index 000000000..7c3141d22
--- /dev/null
+++ b/tests/destructor/smart_ptr.nim
@@ -0,0 +1,49 @@
+
+type
+  SharedPtr*[T] = object
+    val: ptr tuple[atomicCounter: int, value: T]
+
+proc `=destroy`*[T](p: var SharedPtr[T]) =
+  mixin `=destroy`
+  if p.val != nil:
+    let c = atomicDec(p.val[].atomicCounter)
+    if c == 0:
+      `=destroy`(p.val.value)
+      freeShared(p.val)
+    p.val = nil
+
+proc `=`*[T](dest: var SharedPtr[T], src: SharedPtr[T]) {.inline.} =
+  if dest.val != src.val:
+    if dest.val != nil:
+      `=destroy`(dest)
+    if src.val != nil:
+      discard atomicInc(src.val[].atomicCounter)
+    dest.val = src.val
+
+proc `=sink`*[T](dest: var SharedPtr[T], src: SharedPtr[T]) {.inline.} =
+  if dest.val != src.val:
+    if dest.val != nil:
+      `=destroy`(dest)
+    dest.val = src.val
+
+proc newSharedPtr*[T](val: sink T): SharedPtr[T] =
+  result.val = cast[type(result.val)](allocShared0(sizeof(result.val[])))
+  result.val.atomicCounter = 1
+  result.val.value = val
+
+func get*[T](p: SharedPtr[T]): var T {.inline.} =
+  p.val.value
+
+func isNil*[T](p: SharedPtr[T]): bool {.inline.} =
+  p.val == nil
+
+proc cas*[T](p, old_val: var SharedPtr[T], new_val: SharedPtr[T]): bool {.inline.} =
+  if old_val.val == new_val.val:
+    result = true
+  else:
+    result = cas(p.val.addr, old_val.val, new_val.val)
+    if result:
+      `=destroy`(old_val)
+      if new_val.val != nil:
+        discard atomicInc(new_val.val[].atomicCounter)
+