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

Side by Side 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, 9 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 unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright 2014 Google, Inc
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #ifndef SkStackAllocator_DEFINED
9 #define SkStackAllocator_DEFINED
10
11 #include "SkTDArray.h"
12 #include "SkTypes.h"
13
14 /*
15 * Helper for using an SkStackAllocator to create a new object.
16 * @param ptr Raw pointer to typeName. It should be pointing to NULL, since
17 * its old value will be ignored. After this macro finishes, it will point
18 * to a new object of type typeName, allocated by the SkStackAllocator,
19 * which will handle deleting it.
20 * @param allocator Reference to an SkStackAllocator. Will be used to allocate
21 * an object of type typeName. It handles deleting the new object in its
22 * destructor.
23 * @param typeName type of the new object to create.
24 * @param args Arguments to pass to the constructor of the new object, in
25 * parentheses, or () for the default constructor.
26 *
27 * Sample usage:
28 * <code>
29 * SkStackAllocator<100> alloc;
30 * SkBlitter* blitter (NULL);
31 * SkSTACK_ALLOCATE(blitter, alloc, SkNullBlitter, ());
32 * </code>
33 *
34 * After this line, blitter points to a new SkNullBlitter object, which will
35 * be destroyed when alloc goes out of scope.
36 */
37 #define SkSTACK_ALLOCATE(ptr, allocator, typeName, args) \
38 void* buf = allocator.reserveT<typeName>(); \
39 SkNEW_PLACEMENT_ARGS(buf, typeName, args); \
40 ptr = static_cast<typeName*>(buf)
41
42 // Used by SkStackAllocator to call the destructor for objects it has
43 // allocated.
44 template<typename T> void destroyT(void* ptr) {
45 static_cast<T*>(ptr)->~T();
46 }
47
48 /*
49 * 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?
50 * stack. If an object is larger than kSize, it will be allocated on the
51 * heap, This class's destructor will handle calling the destructor for each
52 * object it allocated and freeing its memory.
53 */
54 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
55 public:
56 SkStackAllocator()
57 : fStorageUsed(0)
58 {}
59
60 ~SkStackAllocator() {
61 // Destruct in reverse order, in case an earlier object points to a
62 // later object.
63 while (fObjects.count() > 0) {
64 Triple triple;
65 fObjects.pop(&triple);
66 triple.fKillProc(triple.fObj);
67 // Safe to do if fObj is in fStorage, since fHeapStorage will
68 // point to NULL.
69 sk_free(triple.fHeapStorage);
70 }
71 }
72
73 /*
74 * Create and return space for a T. The space will be on the stack if
75 * there is room, or on the heap otherwise. Either way, this class will
76 * call ~T() in its destructor and free the heap allocation if necessary.
77 *
78 * The caller MUST create a new T in the returned buffer (using
79 * SkNEW_PLACEMENT or SkNEW_PLACEMENT_ARGS), as this class will call ~T()
80 * in its destructor. (FIXME: Can we pass T's constructor's arguments to
81 * 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.
82 */
83 template<typename T> void* reserveT() {
84 const size_t storageRemaining = SkAlign4(kSize) - fStorageUsed;
85 const size_t storageRequired = SkAlign4(sizeof(T));
86 Triple triple;
87 if (storageRequired > storageRemaining) {
88 // Allocate on the heap
89 triple.fHeapStorage = sk_malloc_throw(storageRequired);
90 triple.fObj = static_cast<void*>(triple.fHeapStorage);
91 } else {
92 // There is space in fStorage.
93 triple.fHeapStorage = NULL;
94 SkASSERT(SkIsAlign4(fStorageUsed));
95 triple.fObj = static_cast<void*>(fStorage + (fStorageUsed >> 2));
96 fStorageUsed += storageRequired;
97 }
98 triple.fKillProc = destroyT<T>;
99 fObjects.push(triple);
100 return triple.fObj;
101 }
102
103 private:
104 struct Triple {
105 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
106 void* fHeapStorage;
107 void (*fKillProc)(void*);
108
109 };
110
111 // Number of bytes used so far.
112 size_t fStorageUsed;
113 SkTDArray<Triple> fObjects;
114 // Pad the storage size to be 4-byte aligned.
115 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
116 };
117 // 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
118 #define SkStackAllocator(...) SK_REQUIRE_LOCAL_VAR(SkStackAllocator)
119
120 #endif // SkStackAllocator_DEFINED
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698