ref<T>::ref() now initializes to nullptr. Improve boolean comparisons for ref.
authorRobert Sesek <rsesek@bluestatic.org>
Sun, 9 Oct 2016 00:54:21 +0000 (20:54 -0400)
committerRobert Sesek <rsesek@bluestatic.org>
Sun, 9 Oct 2016 00:54:21 +0000 (20:54 -0400)
Also add internal::OwnedPtrDeleter::operator= to suport std::move of owned.

test.cc
zcpointer.h

diff --git a/test.cc b/test.cc
index e7171d3..95f749d 100644 (file)
--- a/test.cc
+++ b/test.cc
@@ -71,6 +71,55 @@ void TestPtr() {
   EXPECT_UAF(ref->DoThing());
 }
 
+void TestEquality() {
+  zc::owned<C> a(new C());
+  zc::owned<C> b(new C());
+
+  EXPECT(a == a);
+  EXPECT(b == b);
+  EXPECT(a != b);
+
+  zc::ref<C> ra = a.get();
+  zc::ref<C> rb = b.get();
+
+  EXPECT(ra == ra);
+  EXPECT(ra == a.get());
+  EXPECT(rb == rb);
+  EXPECT(rb == b.get());
+
+  EXPECT(rb != ra);
+
+  zc::ref<C> r = a.get();
+  EXPECT(r == ra);
+  EXPECT(r == a.get());
+
+  zc::owned<C> c;
+  zc::owned<C> c2;
+  zc::ref<C> rc = nullptr;
+
+  EXPECT(rc == c.get());
+  EXPECT(c == nullptr);
+  EXPECT(rc == nullptr);
+  EXPECT(a != c);
+  EXPECT(c == c2);
+}
+
+void TestNulls() {
+  zc::owned<C> l;
+  zc::owned<C> r;
+
+  zc::ref<C> rl = l.get();
+  zc::ref<C> rr = r.get();
+
+  r = std::move(l);
+  rl = rr;
+
+  EXPECT(l == nullptr);
+  EXPECT(r == nullptr);
+  EXPECT(rl == nullptr);
+  EXPECT(rr == nullptr);
+}
+
 #define TEST_FUNC(fn) { #fn , Test##fn }
 
 int main() {
@@ -81,6 +130,8 @@ int main() {
     TEST_FUNC(Reset),
     TEST_FUNC(Move),
     TEST_FUNC(Ptr),
+    TEST_FUNC(Equality),
+    TEST_FUNC(Nulls),
   };
 
   bool passed = true;
index 10251c1..b9bb511 100644 (file)
@@ -39,6 +39,10 @@ class OwnedPtrDeleter {
   OwnedPtrDeleter(OwnedPtrDeleter&& other) : refs_(std::move(other.refs_)) {
   }
 
+  void operator=(const OwnedPtrDeleter& o) {
+    refs_ = o.refs_;
+  }
+
   void operator()(T* t) const {
     for (auto& ref : refs_) {
       ref->MarkDeleted();
@@ -86,29 +90,34 @@ class owned : public std::unique_ptr<T, internal::OwnedPtrDeleter<T>> {
 template <typename T>
 class ref {
  public:
-  ref() : ptr_(DeletedSentinel()) {}
+  ref() : ptr_(nullptr) {}
+
+  ref(std::nullptr_t) : ref() {}
 
-  explicit ref(owned<T>& o) : ptr_(&o) {
-    ptr_->get_deleter().AddRef(this);
+  explicit ref(owned<T>& o) : ptr_(nullptr) {
+    if (o != nullptr) {
+      ptr_ = &o;
+      ptr_->get_deleter().AddRef(this);
+    }
   }
 
-  ref(const ref<T>& o) {
-    *this = o;
+  ref(const ref<T>& r) {
+    *this = r;
   }
 
   ref<T>& operator=(const ref<T>& o) {
     ptr_ = o.ptr_;
-    if (!IsDeleted()) {
+    if (ptr_ != nullptr && !IsDeleted()) {
       ptr_->get_deleter().AddRef(this);
     }
     return *this;
   }
 
   ~ref() {
-    if (!IsDeleted()) {
+    if (ptr_ != nullptr && !IsDeleted()) {
       ptr_->get_deleter().RemoveRef(this);
-      MarkDeleted();
     }
+    MarkDeleted();
   }
 
   T* operator->() const {
@@ -116,6 +125,22 @@ class ref {
     return ptr_->operator->();
   }
 
+  bool operator==(const ref<T>& r) const {
+    if (ptr_ == nullptr) {
+      return r.ptr_ == nullptr;
+    } else {
+      return ptr_ == r.ptr_ && *ptr_ == *r.ptr_;
+    }
+  }
+
+  bool operator==(std::nullptr_t) const {
+    return ptr_ == nullptr;
+  }
+
+  bool operator!=(const ref<T>& r) const {
+    return !(*this == r);
+  }
+
  protected:
   friend class internal::OwnedPtrDeleter<T>;