specialize SkDataTable for arrays where all elements are the same size.
optimize impl to not require another level of indirection (SkData) for storage.
add unittests for flattening.
optimize builder to not make a deepcopy of its chunkalloc heap.



git-svn-id: http://skia.googlecode.com/svn/trunk@8790 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/tests/DataRefTest.cpp b/tests/DataRefTest.cpp
index 26c263a..dbe02e8 100644
--- a/tests/DataRefTest.cpp
+++ b/tests/DataRefTest.cpp
@@ -10,6 +10,8 @@
 #include "SkDataSet.h"
 #include "SkDataTable.h"
 #include "SkStream.h"
+#include "SkOrderedReadBuffer.h"
+#include "SkOrderedWriteBuffer.h"
 
 template <typename T> class SkTUnref {
 public:
@@ -23,6 +25,58 @@
     T*  fRef;
 };
 
+static void test_is_equal(skiatest::Reporter* reporter,
+                          const SkDataTable* a, const SkDataTable* b) {
+    REPORTER_ASSERT(reporter, a->count() == b->count());
+    for (int i = 0; i < a->count(); ++i) {
+        size_t sizea, sizeb;
+        const void* mema = a->at(i, &sizea);
+        const void* memb = b->at(i, &sizeb);
+        REPORTER_ASSERT(reporter, sizea == sizeb);
+        REPORTER_ASSERT(reporter, !memcmp(mema, memb, sizea));
+    }
+}
+
+static void test_datatable_flatten(skiatest::Reporter* reporter,
+                                   SkDataTable* table) {
+    SkOrderedWriteBuffer wb(1024);
+    wb.writeFlattenable(table);
+
+    size_t wsize = wb.size();
+    SkAutoMalloc storage(wsize);
+    wb.writeToMemory(storage.get());
+
+    SkOrderedReadBuffer rb(storage.get(), wsize);
+    SkAutoTUnref<SkDataTable> newTable((SkDataTable*)rb.readFlattenable());
+
+    SkDebugf("%d entries, %d flatten-size\n", table->count(), wsize);
+    test_is_equal(reporter, table, newTable);
+}
+
+static void test_datatable_is_empty(skiatest::Reporter* reporter,
+                                    SkDataTable* table) {
+    REPORTER_ASSERT(reporter, table->isEmpty());
+    REPORTER_ASSERT(reporter, 0 == table->count());
+    test_datatable_flatten(reporter, table);
+}
+
+static void test_emptytable(skiatest::Reporter* reporter) {
+    SkAutoTUnref<SkDataTable> table0(SkDataTable::NewEmpty());
+    SkAutoTUnref<SkDataTable> table1(SkDataTable::NewCopyArrays(NULL, NULL, 0));
+    SkAutoTUnref<SkDataTable> table2(SkDataTable::NewCopyArray(NULL, NULL, 0));
+    SkAutoTUnref<SkDataTable> table3(SkDataTable::NewArrayProc(NULL, NULL, 0,
+                                                               NULL, NULL));
+
+    test_datatable_is_empty(reporter, table0);
+    test_datatable_is_empty(reporter, table1);
+    test_datatable_is_empty(reporter, table2);
+    test_datatable_is_empty(reporter, table3);
+
+    test_is_equal(reporter, table0, table1);
+    test_is_equal(reporter, table0, table2);
+    test_is_equal(reporter, table0, table3);
+}
+
 static void test_simpletable(skiatest::Reporter* reporter) {
     const int idata[] = { 1, 4, 9, 16, 25, 63 };
     int icount = SK_ARRAY_COUNT(idata);
@@ -33,9 +87,10 @@
     for (int i = 0; i < icount; ++i) {
         size_t size;
         REPORTER_ASSERT(reporter, sizeof(int) == itable->atSize(i));
-        REPORTER_ASSERT(reporter, *itable->atDataT<int>(i, &size) == idata[i]);
+        REPORTER_ASSERT(reporter, *itable->atT<int>(i, &size) == idata[i]);
         REPORTER_ASSERT(reporter, sizeof(int) == size);
     }
+    test_datatable_flatten(reporter, itable);
 }
 
 static void test_vartable(skiatest::Reporter* reporter) {
@@ -55,13 +110,14 @@
     for (int i = 0; i < count; ++i) {
         size_t size;
         REPORTER_ASSERT(reporter, table->atSize(i) == sizes[i]);
-        REPORTER_ASSERT(reporter, !strcmp(table->atDataT<const char>(i, &size),
+        REPORTER_ASSERT(reporter, !strcmp(table->atT<const char>(i, &size),
                                           str[i]));
         REPORTER_ASSERT(reporter, size == sizes[i]);
 
         const char* s = table->atStr(i);
         REPORTER_ASSERT(reporter, strlen(s) == strlen(str[i]));
     }
+    test_datatable_flatten(reporter, table);
 }
 
 static void test_tablebuilder(skiatest::Reporter* reporter) {
@@ -75,25 +131,47 @@
     for (int i = 0; i < count; ++i) {
         builder.append(str[i], strlen(str[i]) + 1);
     }
-    SkAutoTUnref<SkDataTable> table(builder.createDataTable());
+    SkAutoTUnref<SkDataTable> table(builder.detachDataTable());
 
     REPORTER_ASSERT(reporter, table->count() == count);
     for (int i = 0; i < count; ++i) {
         size_t size;
         REPORTER_ASSERT(reporter, table->atSize(i) == strlen(str[i]) + 1);
-        REPORTER_ASSERT(reporter, !strcmp(table->atDataT<const char>(i, &size),
+        REPORTER_ASSERT(reporter, !strcmp(table->atT<const char>(i, &size),
                                           str[i]));
         REPORTER_ASSERT(reporter, size == strlen(str[i]) + 1);
 
         const char* s = table->atStr(i);
         REPORTER_ASSERT(reporter, strlen(s) == strlen(str[i]));
     }
+    test_datatable_flatten(reporter, table);
 }
 
-static void test_datatable(skiatest::Reporter* reporter) {
+static void test_globaltable(skiatest::Reporter* reporter) {
+    static const int gData[] = {
+        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+    };
+    int count = SK_ARRAY_COUNT(gData);
+
+    SkAutoTUnref<SkDataTable> table(SkDataTable::NewArrayProc(gData,
+                                          sizeof(gData[0]), count, NULL, NULL));
+    
+    REPORTER_ASSERT(reporter, table->count() == count);
+    for (int i = 0; i < count; ++i) {
+        size_t size;
+        REPORTER_ASSERT(reporter, table->atSize(i) == sizeof(int));
+        REPORTER_ASSERT(reporter, *table->atT<const char>(i, &size) == i);
+        REPORTER_ASSERT(reporter, sizeof(int) == size);
+    }
+    test_datatable_flatten(reporter, table);
+}
+
+static void TestDataTable(skiatest::Reporter* reporter) {
+    test_emptytable(reporter);
     test_simpletable(reporter);
     test_vartable(reporter);
     test_tablebuilder(reporter);
+    test_globaltable(reporter);
 }
 
 static void unrefAll(const SkDataSet::Pair pairs[], int count) {
@@ -220,8 +298,8 @@
 
     test_cstring(reporter);
     test_dataset(reporter);
-    test_datatable(reporter);
 }
 
 #include "TestClassDef.h"
 DEFINE_TESTCLASS("Data", DataTestClass, TestData)
+DEFINE_TESTCLASS("DataTable", DataTableTestClass, TestDataTable)