Enhancements and a fix to templated containers.
authorbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 13 Jun 2013 15:13:46 +0000 (15:13 +0000)
committerbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 13 Jun 2013 15:13:46 +0000 (15:13 +0000)
R=robertphillips@google.com

Review URL: https://codereview.chromium.org/16951004

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

include/core/SkTArray.h
include/core/SkTemplates.h

index 46e6687..13c0d71 100644 (file)
@@ -41,6 +41,8 @@ inline void copyAndDelete(SkTArray<T, false>* self, char* newMemArray) {
 
 }
 
+template <typename T, bool MEM_COPY> void* operator new(size_t, SkTArray<T, MEM_COPY>*, int);
+
 /** When MEM_COPY is true T will be bit copied when moved.
     When MEM_COPY is false, T will be copy constructed / destructed.
     In all cases T's constructor will be called on allocation,
@@ -91,7 +93,7 @@ public:
             fItemArray[i].~T();
         }
         fCount = 0;
-        checkRealloc((int)array.count());
+        this->checkRealloc((int)array.count());
         fCount = array.count();
         SkTArrayExt::copy(this, static_cast<const T*>(array.fMemArray));
         return *this;
@@ -159,20 +161,18 @@ public:
      * elements.
      */
     T& push_back() {
-        this->checkRealloc(1);
-        SkNEW_PLACEMENT((char*)fMemArray + sizeof(T) * fCount, T);
-        ++fCount;
-        return fItemArray[fCount-1];
+        T* newT = reinterpret_cast<T*>(this->push_back_raw(1));
+        SkNEW_PLACEMENT(newT, T);
+        return *newT;
     }
 
     /**
      * Version of above that uses a copy constructor to initialize the new item
      */
     T& push_back(const T& t) {
-        this->checkRealloc(1);
-        SkNEW_PLACEMENT_ARGS((char*)fMemArray + sizeof(T) * fCount, T, (t));
-        ++fCount;
-        return fItemArray[fCount-1];
+        T* newT = reinterpret_cast<T*>(this->push_back_raw(1));
+        SkNEW_PLACEMENT_ARGS(newT, T, (t));
+        return *newT;
     }
 
     /**
@@ -182,12 +182,11 @@ public:
      */
     T* push_back_n(int n) {
         SkASSERT(n >= 0);
-        this->checkRealloc(n);
+        T* newTs = reinterpret_cast<T*>(this->push_back_raw(n));
         for (int i = 0; i < n; ++i) {
-            SkNEW_PLACEMENT(fItemArray + fCount + i, T);
+            SkNEW_PLACEMENT(newTs + i, T);
         }
-        fCount += n;
-        return fItemArray + fCount - n;
+        return newTs;
     }
 
     /**
@@ -196,12 +195,11 @@ public:
      */
     T* push_back_n(int n, const T& t) {
         SkASSERT(n >= 0);
-        this->checkRealloc(n);
+        T* newTs = reinterpret_cast<T*>(this->push_back_raw(n));
         for (int i = 0; i < n; ++i) {
-            SkNEW_PLACEMENT_ARGS(fItemArray + fCount + i, T, (t));
+            SkNEW_PLACEMENT_ARGS(newTs[i], T, (t));
         }
-        fCount += n;
-        return fItemArray + fCount - n;
+        return newTs;
     }
 
     /**
@@ -236,7 +234,7 @@ public:
         SkASSERT(fCount >= n);
         fCount -= n;
         for (int i = 0; i < n; ++i) {
-            fItemArray[i].~T();
+            fItemArray[fCount + i].~T();
         }
         this->checkRealloc(0);
     }
@@ -384,6 +382,15 @@ private:
 
     static const int gMIN_ALLOC_COUNT = 8;
 
+    // Helper function that makes space for n objects, adjusts the count, but does not initialize
+    // the new objects.
+    void* push_back_raw(int n) {
+        this->checkRealloc(n);
+        void* ptr = fItemArray + fCount;
+        fCount += n;
+        return ptr;
+    }
+
     inline void checkRealloc(int delta) {
         SkASSERT(fCount >= 0);
         SkASSERT(fAllocCount >= 0);
@@ -418,6 +425,8 @@ private:
         }
     }
 
+    friend void* operator new<T>(size_t, SkTArray*, int);
+
     template<typename X> friend void SkTArrayExt::copy(SkTArray<X, true>* that, const X*);
     template<typename X> friend void SkTArrayExt::copyAndDelete(SkTArray<X, true>* that, char*);
 
@@ -434,6 +443,21 @@ private:
     };
 };
 
+// Use the below macro (SkNEW_APPEND_TO_TARRAY) rather than calling this directly
+template <typename T, bool MEM_COPY>
+void* operator new(size_t, SkTArray<T, MEM_COPY>* array, int atIndex) {
+    // Currently, we only support adding to the end of the array. When the array class itself
+    // supports random insertion then this should be updated.
+    // SkASSERT(atIndex >= 0 && atIndex <= array->count());
+    SkASSERT(atIndex == array->count());
+    return array->push_back_raw(1);
+}
+
+// Constructs a new object as the last element of an SkTArray.
+#define SkNEW_APPEND_TO_TARRAY(array_ptr, type_name, args)  \
+    (new ((array_ptr), (array_ptr)->count()) type_name args)
+
+
 /**
  * Subclass of SkTArray that contains a preallocated memory block for the array.
  */
index e8a8b61..3060f9e 100644 (file)
@@ -228,33 +228,53 @@ private:
  */
 template <size_t N, typename T> class SkAutoSTArray : SkNoncopyable {
 public:
+    /** Initialize with no objects */
+    SkAutoSTArray() {
+        fArray = NULL;
+        fCount = 0;
+    }
+
     /** Allocate count number of T elements
      */
     SkAutoSTArray(size_t count) {
-        fCount = count;
-        if (count > N) {
-            fArray = (T*) sk_malloc_throw(count * sizeof(T));
-        } else if (count > 0) {
-            fArray = (T*) fStorage;
-        } else {
-            fArray = NULL;
-            return;
-        }
-        T* iter = fArray;
-        T* stop = fArray + count;
-        while (iter < stop) {
-            SkNEW_PLACEMENT(iter++, T);
-        }
+        fArray = NULL;
+        fCount = 0;
+        this->reset(count);
     }
 
     ~SkAutoSTArray() {
+        this->reset(0);
+    }
+
+    /** Destroys previous objects in the array and default constructs count number of objects */
+    void reset(size_t count) {
         T* start = fArray;
         T* iter = start + fCount;
         while (iter > start) {
             (--iter)->~T();
         }
-        if (fCount > N) {
-            sk_free(fArray);
+
+        if (fCount != count) {
+            if (count > N) {
+                sk_free(fArray);
+            }
+
+            if (count > N) {
+                fArray = (T*) sk_malloc_throw(count * sizeof(T));
+            } else if (count > 0) {
+                fArray = (T*) fStorage;
+            } else {
+                fArray = NULL;
+                return;
+            }
+
+            fCount = count;
+        }
+
+        iter = fArray;
+        T* stop = fArray + count;
+        while (iter < stop) {
+            SkNEW_PLACEMENT(iter++, T);
         }
     }