Partially restore small-T optimization for very small (empty) T.
authorcommit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 7 May 2014 18:01:57 +0000 (18:01 +0000)
committercommit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 7 May 2014 18:01:57 +0000 (18:01 +0000)
This is particularly helpful for SkRecord::replace<NoOp>, which now doesn't go
off and allocate a pointless byte.

BUG=skia:2378
R=fmalita@chromium.org, bungeman@google.com, mtklein@google.com

Author: mtklein@chromium.org

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

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

src/record/SkRecord.h
src/utils/SkTLogic.h

index b1e4ae24f8da69b5e60aecad189573dbd448c9fd..ccfa1dd556441011df4c17f2ff827f560d064f4d 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "SkChunkAlloc.h"
 #include "SkRecords.h"
+#include "SkTLogic.h"
 #include "SkTemplates.h"
 
 // SkRecord (REC-ord) represents a sequence of SkCanvas calls, saved for future use.
@@ -77,7 +78,7 @@ public:
         }
 
         fTypes[fCount] = T::kType;
-        return fRecords[fCount++].set(this->alloc<T>());
+        return fRecords[fCount++].set(this->allocCommand<T>());
     }
 
     // Replace the i-th command with a new command of type T.
@@ -91,7 +92,7 @@ public:
         this->mutate(i, destroyer);
 
         fTypes[i] = T::kType;
-        return fRecords[i].set(this->alloc<T>());
+        return fRecords[i].set(this->allocCommand<T>());
     }
 
     // Replace the i-th command with a new command of type T.
@@ -105,7 +106,7 @@ public:
         SkASSERT(proofOfAdoption == fRecords[i].ptr<Existing>());
 
         fTypes[i] = T::kType;
-        return fRecords[i].set(this->alloc<T>());
+        return fRecords[i].set(this->allocCommand<T>());
     }
 
 private:
@@ -162,6 +163,17 @@ private:
         uint8_t fType;
     };
 
+    // No point in allocating any more than one of an empty struct.
+    // We could just return NULL but it's sort of confusing to return NULL on success.
+    template <typename T>
+    SK_WHEN(SkTIsEmpty<T>, T*) allocCommand() {
+        static T singleton;
+        return &singleton;
+    }
+
+    template <typename T>
+    SK_WHEN(!SkTIsEmpty<T>, T*) allocCommand() { return this->alloc<T>(); }
+
     // An untyped pointer to some bytes in fAlloc.  This is the interface for polymorphic dispatch:
     // visit() and mutate() work with the parallel fTypes array to do the work of a vtable.
     struct Record {
index 925d4bdcd4fb3d514d0197f10d5815165aa120e6..2b5df0b16fe866559a846790ae1ecef380cfda38 100644 (file)
@@ -30,6 +30,14 @@ template <typename T, T v> struct SkTIntegralConstant {
 /** Convenience specialization of SkTIntegralConstant. */
 template <bool b> struct SkTBool : SkTIntegralConstant<bool, b> { };
 
+/** Pre-C++11 version of std::is_empty<T>. */
+template <typename T>
+class SkTIsEmpty {
+    struct Derived : public T { char unused; };
+public:
+    static const bool value = sizeof(Derived) == sizeof(char);
+};
+
 /** Pre-C++11 version of std::true_type. */
 typedef SkTBool<true> SkTrue;