add SkTRefArray, in hopes that it will enable more sharing between pictureplaybacks
in different threads.



git-svn-id: http://skia.googlecode.com/svn/trunk@4709 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkTRefArray.h b/src/core/SkTRefArray.h
new file mode 100755
index 0000000..f352cf1
--- /dev/null
+++ b/src/core/SkTRefArray.h
@@ -0,0 +1,78 @@
+//
+//  SkTRefArray.h
+//  core
+//
+//  Created by Mike Reed on 7/17/12.
+//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
+//
+
+#ifndef SkTRefArray_DEFINED
+#define SkTRefArray_DEFINED
+
+#include "SkThread.h"
+
+/**
+ *  Wrapper to manage thread-safe sharing of an array of T objects. The array
+ *  cannot be grown or shrunk.
+ */
+template <typename T> class SkTRefArray {
+public:
+    static SkTRefArray<T>* Create(int count) {
+        size_t size = sizeof(SkTRefArray<T>) + count * sizeof(T);
+        SkTRefArray<T>* obj = (SkTRefArray<T>*)sk_malloc_throw(size);
+        
+        obj->fCount = count;
+        obj->fRefCnt = 1;
+        
+        T* array = const_cast<T*>(obj->begin());
+        for (int i = 0; i < count; ++i) {
+            new (&array[i]) T;
+        }
+        
+        return obj;
+    }
+
+    int count() const { return fCount; }
+    const T* begin() const { return (const T*)(this + 1); }
+    const T* end() const { return (const T*)(this + 1) + fCount; }
+    const T& operator[](int index) const {
+        SkASSERT((unsigned)index < (unsigned)fCount);
+        return this->begin()[index];
+    }
+
+    // We mimic SkRefCnt in API, but we don't inherit as we want to control
+    // the allocation/deallocation so we can keep the array in the same
+    // block of memory
+
+    int32_t getRefCnt() const { return fRefCnt; }
+
+    void ref() const {
+        SkASSERT(fRefCnt > 0);
+        sk_atomic_inc(&fRefCnt);
+    }
+    
+    void unref() const {
+        SkASSERT(fRefCnt > 0);
+        if (sk_atomic_dec(&fRefCnt) == 1) {
+            sk_membar_aquire__after_atomic_dec();
+            this->deleteAll();
+            sk_free((void*)this);
+        }
+    }
+
+private:
+    int             fCount;
+    mutable int32_t fRefCnt;
+
+    void deleteAll() const {
+        T* array = const_cast<T*>(this->begin());
+        int n = fCount;
+
+        for (int i = 0; i < n; ++i) {
+            array->~T();
+            array += 1;
+        }
+    }
+};
+
+#endif
diff --git a/tests/RefCntTest.cpp b/tests/RefCntTest.cpp
index 4d4ae3f..569e4e4 100644
--- a/tests/RefCntTest.cpp
+++ b/tests/RefCntTest.cpp
@@ -11,9 +11,34 @@
 #include "SkRefCnt.h"
 #include "SkThreadUtils.h"
 #include "SkWeakRefCnt.h"
+#include "SkTRefArray.h"
 
 ///////////////////////////////////////////////////////////////////////////////
 
+class InstCounterClass {
+public:
+    InstCounterClass() {  gInstCounter += 1; }
+    ~InstCounterClass() { gInstCounter -= 1; }
+
+    static int gInstCounter;
+};
+
+int InstCounterClass::gInstCounter;
+
+static void test_refarray(skiatest::Reporter* reporter) {
+    REPORTER_ASSERT(reporter, 0 == InstCounterClass::gInstCounter);
+
+    int N = 10;
+    SkTRefArray<InstCounterClass>* array = SkTRefArray<InstCounterClass>::Create(N);
+    REPORTER_ASSERT(reporter, 1 == array->getRefCnt());
+
+    REPORTER_ASSERT(reporter, N == InstCounterClass::gInstCounter);
+    REPORTER_ASSERT(reporter, array->count() == N);
+
+    array->unref();
+    REPORTER_ASSERT(reporter, 0 == InstCounterClass::gInstCounter);
+}
+
 static void bounce_ref(void* data) {
     SkRefCnt* ref = static_cast<SkRefCnt*>(data);
     for (int i = 0; i < 100000; ++i) {
@@ -89,6 +114,7 @@
 static void test_refCntTests(skiatest::Reporter* reporter) {
     test_refCnt(reporter);
     test_weakRefCnt(reporter);
+    test_refarray(reporter);
 }
 
 #include "TestClassDef.h"