Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(150)

Unified Diff: src/core/SkStackAllocator.h

Issue 179343005: Add a class to allocate small objects w/o extra calls to new. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/core/SkStackAllocator.h
diff --git a/src/core/SkStackAllocator.h b/src/core/SkStackAllocator.h
new file mode 100644
index 0000000000000000000000000000000000000000..8de02977adae070734ef8230e2b7c446cc0c6aec
--- /dev/null
+++ b/src/core/SkStackAllocator.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2014 Google, Inc
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkStackAllocator_DEFINED
+#define SkStackAllocator_DEFINED
+
+#include "SkTDArray.h"
+#include "SkTypes.h"
+
+/*
+ * Helper for using an SkStackAllocator to create a new object.
+ * @param ptr Raw pointer to typeName. It should be pointing to NULL, since
+ * its old value will be ignored. After this macro finishes, it will point
+ * to a new object of type typeName, allocated by the SkStackAllocator,
+ * which will handle deleting it.
+ * @param allocator Reference to an SkStackAllocator. Will be used to allocate
+ * an object of type typeName. It handles deleting the new object in its
+ * destructor.
+ * @param typeName type of the new object to create.
+ * @param args Arguments to pass to the constructor of the new object, in
+ * parentheses, or () for the default constructor.
+ *
+ * Sample usage:
+ * <code>
+ * SkStackAllocator<100> alloc;
+ * SkBlitter* blitter (NULL);
+ * SkSTACK_ALLOCATE(blitter, alloc, SkNullBlitter, ());
+ * </code>
+ *
+ * After this line, blitter points to a new SkNullBlitter object, which will
+ * be destroyed when alloc goes out of scope.
+ */
+#define SkSTACK_ALLOCATE(ptr, allocator, typeName, args) \
+ void* buf = allocator.reserveT<typeName>(); \
+ SkNEW_PLACEMENT_ARGS(buf, typeName, args); \
+ ptr = static_cast<typeName*>(buf)
+
+// Used by SkStackAllocator to call the destructor for objects it has
+// allocated.
+template<typename T> void destroyT(void* ptr) {
+ static_cast<T*>(ptr)->~T();
+}
+
+/*
+ * Template class for allocating small (as defined by kSize) objects on the
mtklein 2014/02/27 23:40:54 This sort of reads like we'll be able to allocate
scroggo 2014/03/05 20:25:52 Correct. I've updated the comment. Sound better?
+ * stack. If an object is larger than kSize, it will be allocated on the
+ * heap, This class's destructor will handle calling the destructor for each
+ * object it allocated and freeing its memory.
+ */
+template<size_t kSize> class SkStackAllocator : public SkNoncopyable {
mtklein 2014/02/27 23:40:54 It looked like we're generally using this to alloc
scroggo 2014/03/05 20:25:52 Actually, no. The Sk3DBlitter will be allocated by
+public:
+ SkStackAllocator()
+ : fStorageUsed(0)
+ {}
+
+ ~SkStackAllocator() {
+ // Destruct in reverse order, in case an earlier object points to a
+ // later object.
+ while (fObjects.count() > 0) {
+ Triple triple;
+ fObjects.pop(&triple);
+ triple.fKillProc(triple.fObj);
+ // Safe to do if fObj is in fStorage, since fHeapStorage will
+ // point to NULL.
+ sk_free(triple.fHeapStorage);
+ }
+ }
+
+ /*
+ * Create and return space for a T. The space will be on the stack if
+ * there is room, or on the heap otherwise. Either way, this class will
+ * call ~T() in its destructor and free the heap allocation if necessary.
+ *
+ * The caller MUST create a new T in the returned buffer (using
+ * SkNEW_PLACEMENT or SkNEW_PLACEMENT_ARGS), as this class will call ~T()
+ * in its destructor. (FIXME: Can we pass T's constructor's arguments to
+ * this function so we can create the object as well?)
bungeman-skia 2014/02/27 18:26:01 With perfect forwarding in c++11 you can. With c++
mtklein 2014/02/27 18:51:02 A good compromise is to make a few versions: temp
scroggo 2014/03/05 20:25:52 Done.
+ */
+ template<typename T> void* reserveT() {
+ const size_t storageRemaining = SkAlign4(kSize) - fStorageUsed;
+ const size_t storageRequired = SkAlign4(sizeof(T));
+ Triple triple;
+ if (storageRequired > storageRemaining) {
+ // Allocate on the heap
+ triple.fHeapStorage = sk_malloc_throw(storageRequired);
+ triple.fObj = static_cast<void*>(triple.fHeapStorage);
+ } else {
+ // There is space in fStorage.
+ triple.fHeapStorage = NULL;
+ SkASSERT(SkIsAlign4(fStorageUsed));
+ triple.fObj = static_cast<void*>(fStorage + (fStorageUsed >> 2));
+ fStorageUsed += storageRequired;
+ }
+ triple.fKillProc = destroyT<T>;
+ fObjects.push(triple);
+ return triple.fObj;
+ }
+
+private:
+ struct Triple {
+ void* fObj;
mtklein 2014/02/27 23:40:54 If you really want to keep things small, we might
scroggo 2014/03/05 20:25:52 Interesting idea! Are we guaranteed the bottom bit
+ void* fHeapStorage;
+ void (*fKillProc)(void*);
+
+ };
+
+ // Number of bytes used so far.
+ size_t fStorageUsed;
+ SkTDArray<Triple> fObjects;
+ // Pad the storage size to be 4-byte aligned.
+ uint32_t fStorage[SkAlign4(kSize) >> 2];
mtklein 2014/02/27 23:40:54 Consider storing everything in fStorage? Does it
scroggo 2014/03/05 20:25:52 That's a very good point. I've removed the SkTDArr
+};
+// This class only makes sense on the stack.
mtklein 2014/02/27 23:40:54 This doesn't strictly have to be on the stack righ
scroggo 2014/03/05 20:25:52 Agreed. Renamed SkSmallAllocator. And I've remove
+#define SkStackAllocator(...) SK_REQUIRE_LOCAL_VAR(SkStackAllocator)
+
+#endif // SkStackAllocator_DEFINED

Powered by Google App Engine
This is Rietveld 408576698