Add initializer_list support to SkTArray.

Also added unit tests for each of SkTArray's various constructors, and
added `SkTArray::value_type` which allows calling code to refer to the
array's value-type. These unit tests exposed some preexisting strict-
aliasing issues in SkSTArray when compiled on GCC 6+ with optimizations
enabled, which are being investigated separately at skia:10891.

Change-Id: Ia0fb18830cfbbdcb1545fe7f7ac51d8e768a3f94
Bug: skia:10891
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/330279
Commit-Queue: John Stiles <johnstiles@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
diff --git a/include/private/SkTArray.h b/include/private/SkTArray.h
index d8e43cb..5094a2c 100644
--- a/include/private/SkTArray.h
+++ b/include/private/SkTArray.h
@@ -17,6 +17,7 @@
 #include "include/private/SkTo.h"
 
 #include <string.h>
+#include <initializer_list>
 #include <memory>
 #include <new>
 #include <utility>
@@ -33,6 +34,8 @@
 */
 template <typename T, bool MEM_MOVE = false> class SkTArray {
 public:
+    using value_type = T;
+
     /**
      * Creates an empty array with no initial storage
      */
@@ -81,6 +84,13 @@
         this->init(count);
         this->copy(array);
     }
+    /**
+     * Creates a SkTArray by copying contents of an initializer list.
+     */
+    SkTArray(std::initializer_list<T> data) {
+        this->init(data.size());
+        this->copy(&*data.begin());
+    }
 
     SkTArray& operator=(const SkTArray& that) {
         if (this == &that) {
@@ -361,7 +371,7 @@
     size_t size() const { return (size_t)fCount; }
     void resize(size_t count) { this->resize_back((int)count); }
 
-   /**
+    /**
      * Get the i^th element.
      */
     T& operator[] (int i) {
@@ -473,6 +483,17 @@
         this->copy(array);
     }
 
+    /**
+     * Copy the contents of an initializer list, using preallocated storage if
+     * preAllocCount >= count. Otherwise storage will only be used when array
+     * shrinks to fit.
+     */
+    template <int N>
+    SkTArray(std::initializer_list<T> data, SkAlignedSTStorage<N,T>* storage) {
+        this->initWithPreallocatedStorage(data.size(), storage->get(), N);
+        this->copy(&*data.begin());
+    }
+
 private:
     void init(int count = 0, int reserveCount = 0) {
         fCount = SkToU32(count);
@@ -606,7 +627,7 @@
 /**
  * Subclass of SkTArray that contains a preallocated memory block for the array.
  */
-template <int N, typename T, bool MEM_MOVE= false>
+template <int N, typename T, bool MEM_MOVE = false>
 class SkSTArray : public SkTArray<T, MEM_MOVE> {
 private:
     using INHERITED = SkTArray<T, MEM_MOVE>;
@@ -639,6 +660,10 @@
         : INHERITED(array, count, &fStorage) {
     }
 
+    SkSTArray(std::initializer_list<T> data)
+        : INHERITED(data, &fStorage) {
+    }
+
     SkSTArray& operator=(const SkSTArray& array) {
         INHERITED::operator=(array);
         return *this;
diff --git a/tests/TArrayTest.cpp b/tests/TArrayTest.cpp
index 30f5446..5859960 100644
--- a/tests/TArrayTest.cpp
+++ b/tests/TArrayTest.cpp
@@ -57,7 +57,61 @@
     REPORTER_ASSERT(reporter, a[1] == 3);
     REPORTER_ASSERT(reporter, a[2] == 2);
 
-    // {0, 3, 2 }
+    // { 0, 3, 2 }
+}
+
+template <typename T> static void test_construction(skiatest::Reporter* reporter) {
+    // No arguments: Creates an empty array with no initial storage.
+    T arrayNoArgs;
+    REPORTER_ASSERT(reporter, arrayNoArgs.empty());
+
+    // Single integer: Creates an empty array that will preallocate space for reserveCount elements.
+    T arrayReserve(15);
+    REPORTER_ASSERT(reporter, arrayReserve.empty());
+    REPORTER_ASSERT(reporter, arrayReserve.capacity() == 15);
+
+    // Another array, const&: Copies one array to another.
+    T arrayInitial;
+    arrayInitial.push_back(1);
+    arrayInitial.push_back(2);
+    arrayInitial.push_back(3);
+
+    T arrayCopy(arrayInitial);
+    REPORTER_ASSERT(reporter, arrayInitial.size() == 3);
+    REPORTER_ASSERT(reporter, arrayInitial[0] == 1);
+    REPORTER_ASSERT(reporter, arrayInitial[1] == 2);
+    REPORTER_ASSERT(reporter, arrayInitial[2] == 3);
+    REPORTER_ASSERT(reporter, arrayCopy.size() == 3);
+    REPORTER_ASSERT(reporter, arrayCopy[0] == 1);
+    REPORTER_ASSERT(reporter, arrayCopy[1] == 2);
+    REPORTER_ASSERT(reporter, arrayCopy[2] == 3);
+
+    // Another array, &&: Moves one array to another.
+    T arrayMove(std::move(arrayInitial));
+    REPORTER_ASSERT(reporter, arrayInitial.empty()); // NOLINT(bugprone-use-after-move)
+    REPORTER_ASSERT(reporter, arrayMove.size() == 3);
+    REPORTER_ASSERT(reporter, arrayMove[0] == 1);
+    REPORTER_ASSERT(reporter, arrayMove[1] == 2);
+    REPORTER_ASSERT(reporter, arrayMove[2] == 3);
+
+    // Pointer and count: Copies contents of a standard C array.
+    typename T::value_type data[3] = { 7, 8, 9 };
+    T arrayPtrCount(data, 3);
+    REPORTER_ASSERT(reporter, arrayPtrCount.size() == 3);
+    REPORTER_ASSERT(reporter, arrayPtrCount[0] == 7);
+    REPORTER_ASSERT(reporter, arrayPtrCount[1] == 8);
+    REPORTER_ASSERT(reporter, arrayPtrCount[2] == 9);
+
+    // Initializer list.
+    T arrayInitializer{8, 6, 7, 5, 3, 0, 9};
+    REPORTER_ASSERT(reporter, arrayInitializer.size() == 7);
+    REPORTER_ASSERT(reporter, arrayInitializer[0] == 8);
+    REPORTER_ASSERT(reporter, arrayInitializer[1] == 6);
+    REPORTER_ASSERT(reporter, arrayInitializer[2] == 7);
+    REPORTER_ASSERT(reporter, arrayInitializer[3] == 5);
+    REPORTER_ASSERT(reporter, arrayInitializer[4] == 3);
+    REPORTER_ASSERT(reporter, arrayInitializer[5] == 0);
+    REPORTER_ASSERT(reporter, arrayInitializer[6] == 9);
 }
 
 template <typename T> static void test_swap(skiatest::Reporter* reporter,
@@ -249,4 +303,12 @@
     test_reserve<SkSTArray<1, int>>(reporter);
     test_reserve<SkSTArray<2, int>>(reporter);
     test_reserve<SkSTArray<16, int>>(reporter);
+
+    test_construction<SkTArray<int>>(reporter);
+    test_construction<SkTArray<double>>(reporter);
+#ifndef __GNUC__  // TODO(skbug.com/10891): SkSTArray generates bad code in GCC -fstrict-aliasing
+    test_construction<SkSTArray<1, int>>(reporter);
+    test_construction<SkSTArray<5, char>>(reporter);
+    test_construction<SkSTArray<10, float>>(reporter);
+#endif
 }