Specialize SkAutoTUnref on const T so that operator -> works.
authorbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 27 Jul 2012 13:27:35 +0000 (13:27 +0000)
committerbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 27 Jul 2012 13:27:35 +0000 (13:27 +0000)
Review URL: http://codereview.appspot.com/6450054/

git-svn-id: http://skia.googlecode.com/svn/trunk@4802 2bbb7eff-a529-9590-31e7-b0007b416f81

include/core/SkRefCnt.h

index 79a28ef..eab3c46 100644 (file)
@@ -135,12 +135,14 @@ template <typename T> static inline void SkSafeUnref(T* obj) {
 ///////////////////////////////////////////////////////////////////////////////
 
 /**
- *  Utility class that simply unref's its argument in the destructor.
+ * SkAutoTUnref is a utility class that simply unref's its argument in the
+ * destructor. For implementation detail reasons there is a base class, a
+ * derived general class, and a const-specialized derived class.
  */
-template <typename T> class SkAutoTUnref : SkNoncopyable {
+
+template <typename T> class SkAutoTUnrefBase : SkNoncopyable {
 public:
-    explicit SkAutoTUnref(T* obj = NULL) : fObj(obj) {}
-    ~SkAutoTUnref() { SkSafeUnref(fObj); }
+    ~SkAutoTUnrefBase() { SkSafeUnref(fObj); }
 
     T* get() const { return fObj; }
 
@@ -161,9 +163,11 @@ public:
         return obj;
     }
 
+    operator T*() { return fObj; }
+
     /**
-     * BlockRef<B> is a type which inherits from B, cannot be created,
-     * and makes ref and unref private.
+     * BlockRef<B> is a type which inherits from B, cannot be created, and makes
+     * ref and unref private.
      */
     template<typename B> class BlockRef : public B {
     private:
@@ -171,19 +175,46 @@ public:
         void ref() const;
         void unref() const;
     };
+
+protected:
+    explicit SkAutoTUnrefBase(T* obj) : fObj(obj) {}
+    T*  fObj;
+
+private:
+    SkAutoTUnrefBase();
+};
+
+template <typename T> class SkAutoTUnref : public SkAutoTUnrefBase<T> {
+public:
+    explicit SkAutoTUnref(T* obj = NULL) : SkAutoTUnrefBase<T>(obj) {}
+
     /**
      *  SkAutoTUnref assumes ownership of the ref. As a result, it is an error
      *  for the user to ref or unref through SkAutoTUnref. Therefore
      *  SkAutoTUnref::operator-> returns BlockRef<T>*. This prevents use of
      *  skAutoTUnrefInstance->ref() and skAutoTUnrefInstance->unref().
      */
-    BlockRef<T> *operator->() const {
-        return static_cast<BlockRef<T>*>(fObj);
+    typedef typename SkAutoTUnrefBase<T>::template BlockRef<T> BlockRefT;
+
+    BlockRefT* operator->() const {
+        return static_cast<BlockRefT*>(this->fObj);
     }
-    operator T*() { return fObj; }
+};
 
-private:
-    T*  fObj;
+template <typename T> class SkAutoTUnref<const T> : public SkAutoTUnrefBase<const T> {
+public:
+    explicit SkAutoTUnref(const T* obj = NULL) : SkAutoTUnrefBase<const T>(obj) {}
+    /**
+     *  SkAutoTUnref assumes ownership of the ref. As a result, it is an error
+     *  for the user to ref or unref through SkAutoTUnref. Therefore
+     *  SkAutoTUnref::operator-> returns BlockRef<T>*. This prevents use of
+     *  skAutoTUnrefInstance->ref() and skAutoTUnrefInstance->unref().
+     */
+    typedef typename SkAutoTUnrefBase<const T>::template BlockRef<T> BlockRefT;
+
+    const BlockRefT* operator->() const {
+        return static_cast<const BlockRefT*>(this->fObj);
+    }
 };
 
 class SkAutoUnref : public SkAutoTUnref<SkRefCnt> {