5231803703c2 — Leonard Ritter 13 days ago
* `Rc`: `Weak` can be instantiated as an empty weak reference
* `Rc`: `'clone` method (aliased through `Rc.clone`) for `Weak` can be used to duplicate weak references
* `Rc`: added equality test for weak references
2 files changed, 63 insertions(+), 19 deletions(-)

M lib/scopes/Rc.sc
M testing/test_rc.sc
M lib/scopes/Rc.sc +46 -19
@@ 41,7 41,8 @@ inline gen-type (T)
         let Type = T
         let RcType = RcType
 
-        inline... __typecall (cls, value : RcType)
+        inline... __typecall
+        case (cls, value : RcType)
             let md = (extractvalue value METADATA_INDEX)
             let refcount =
                 getelementptr

          
@@ 50,6 51,10 @@ inline gen-type (T)
             let rc = (add (load refcount) 1)
             store rc refcount
             bitcast (dupe (view value)) this-type
+        case (cls)
+            # null-weak that will never upgrade
+            let self = (nullof storage-type)
+            bitcast self this-type
 
     typedef+ RcType
         let Type = T

          
@@ 77,17 82,17 @@ typedef UpgradeError : (tuple)
 typedef+ ReferenceCounted
     fn strong-count (value)
         viewing value
-        load
-            getelementptr
-                extractvalue value METADATA_INDEX
-                \ 0 STRONGRC_INDEX
+        let md = (extractvalue value METADATA_INDEX)
+        if (not (ptrtoint md usize))
+            return 0
+        load (getelementptr md 0 STRONGRC_INDEX)
 
     fn weak-count (value)
         viewing value
-        load
-            getelementptr
-                extractvalue value METADATA_INDEX
-                \ 0 WEAKRC_INDEX
+        let md = (extractvalue value METADATA_INDEX)
+        if (not (ptrtoint md usize))
+            return 1
+        load (getelementptr md 0 WEAKRC_INDEX)
 
 typedef+ Weak
     inline... __typecall

          
@@ 96,6 101,8 @@ typedef+ Weak
 
     fn _drop (self)
         let md = (extractvalue self METADATA_INDEX)
+        if (not (ptrtoint md usize))
+            return;
         let refcount = (getelementptr md 0 WEAKRC_INDEX)
         let rc = (sub (load refcount) 1)
         assert (rc >= 0) "corrupt refcount encountered"

          
@@ 109,12 116,29 @@ typedef+ Weak
     inline __drop (self)
         _drop (deref self)
 
+    @@ memo
+    inline __== (cls other-cls)
+        static-if (cls == other-cls)
+            fn (self other)
+                == (extractvalue self METADATA_INDEX) (extractvalue other METADATA_INDEX)
+
+
+    fn clone (self)
+        viewing self
+        let md = (extractvalue self METADATA_INDEX)
+        if (ptrtoint md usize)
+            let refcount =
+                getelementptr md 0 WEAKRC_INDEX
+            let rc = (add (load refcount) 1)
+            store rc refcount
+        deref (dupe self)
+
     fn upgrade (self)
         viewing self
-        let refcount =
-            getelementptr
-                extractvalue self METADATA_INDEX
-                \ 0 STRONGRC_INDEX
+        let md = (extractvalue self METADATA_INDEX)
+        if (not (ptrtoint md usize))
+            raise (UpgradeError)
+        let refcount = (getelementptr md 0 STRONGRC_INDEX)
         let rc = (load refcount)
         assert (rc >= 0) "corrupt refcount encountered"
         if (rc == 0)

          
@@ 126,10 150,9 @@ typedef+ Weak
 
     fn force-upgrade (self)
         viewing self
-        let refcount =
-            getelementptr
-                extractvalue self METADATA_INDEX
-                \ 0 STRONGRC_INDEX
+        let md = (extractvalue self METADATA_INDEX)
+        assert (ptrtoint md usize) "upgrading Weak failed"
+        let refcount = (getelementptr md 0 STRONGRC_INDEX)
         let rc = (load refcount)
         assert (rc >= 0) "corrupt refcount encountered"
         assert (rc > 0) "upgrading Weak failed"

          
@@ 147,7 170,8 @@ typedef+ Rc
     inline new (T args...)
         (gen-type T) args...
 
-    fn... clone (value : Rc,)
+    fn... clone
+    case (value : Rc,)
         viewing value
         let refcount =
             getelementptr

          
@@ 156,12 180,15 @@ typedef+ Rc
         let rc = (add (load refcount) 1)
         store rc refcount
         deref (dupe value)
+    case (value : Weak,)
+        viewing value
+        'clone value
 
     inline wrap (value)
         ((gen-type (typeof value)) . wrap) value
 
     let _view = view
-    inline view (self)
+    inline... view (self : Rc,)
         ptrtoref (deref (extractvalue self PAYLOAD_INDEX))
 
     inline __countof (self)

          
M testing/test_rc.sc +17 -0
@@ 42,6 42,17 @@ do
     test ((Rc.strong-count c) == 1)
     test ((Rc.weak-count c) == 0)
 
+    let nullweak = ((Weak vec3))
+    test ((Rc.strong-count nullweak) == 0)
+    test ((Rc.weak-count nullweak) == 1)
+    let nullweak2 = ((Weak vec3))
+    test ((Rc.weak-count nullweak) == 1)
+    test ((Rc.weak-count nullweak2) == 1)
+    test-error ('upgrade nullweak2)
+    let nullweak3 = ('clone nullweak)
+    test (nullweak == nullweak2)
+    test (nullweak == nullweak3)
+
     let w = (c as Weak)
 
     test ((Rc.strong-count c) == 1)

          
@@ 59,6 70,12 @@ do
     test ((Rc.strong-count p) == 2)
     test ((Rc.weak-count p) == 1)
 
+    let w2 = (Rc.clone w)
+    test ((Rc.strong-count p) == 2)
+    test ((Rc.weak-count p) == 2)
+    test (w == w2)
+    drop w2
+
     print c
     test (c.xz == (vec2 1 3))
     drop c