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
}