Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkAutoMalloc.h
Go to the documentation of this file.
1/*
2 * Copyright 2016 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 SkAutoMalloc_DEFINED
9#define SkAutoMalloc_DEFINED
10
15
16#include <cstddef>
17#include <cstdint>
18#include <memory>
19
20/**
21 * Manage an allocated block of heap memory. This object is the sole manager of
22 * the lifetime of the block, so the caller must not call sk_free() or delete
23 * on the block, unless release() was called.
24 */
26public:
27 explicit SkAutoMalloc(size_t size = 0)
28 : fPtr(size ? sk_malloc_throw(size) : nullptr), fSize(size) {}
29
30 /**
31 * Passed to reset to specify what happens if the requested size is smaller
32 * than the current size (and the current block was dynamically allocated).
33 */
34 enum OnShrink {
35 /**
36 * If the requested size is smaller than the current size, and the
37 * current block is dynamically allocated, free the old block and
38 * malloc a new block of the smaller size.
39 */
41
42 /**
43 * If the requested size is smaller than the current size, and the
44 * current block is dynamically allocated, just return the old
45 * block.
46 */
48 };
49
50 /**
51 * Reallocates the block to a new size. The ptr may or may not change.
52 */
53 void* reset(size_t size = 0, OnShrink shrink = kAlloc_OnShrink) {
54 if (size != fSize && (size > fSize || kReuse_OnShrink != shrink)) {
55 fPtr.reset(size ? sk_malloc_throw(size) : nullptr);
56 fSize = size;
57 }
58 return fPtr.get();
59 }
60
61 /**
62 * Return the allocated block.
63 */
64 void* get() { return fPtr.get(); }
65 const void* get() const { return fPtr.get(); }
66
67 /** Transfer ownership of the current ptr to the caller, setting the
68 internal reference to null. Note the caller is reponsible for calling
69 sk_free on the returned address.
70 */
71 void* release() {
72 fSize = 0;
73 return fPtr.release();
74 }
75
76private:
77 struct WrapFree {
78 void operator()(void* p) { sk_free(p); }
79 };
80 std::unique_ptr<void, WrapFree> fPtr;
81 size_t fSize; // can be larger than the requested size (see kReuse)
82};
83
84/**
85 * Manage an allocated block of memory. If the requested size is <= kSizeRequested (or slightly
86 * more), then the allocation will come from the stack rather than the heap. This object is the
87 * sole manager of the lifetime of the block, so the caller must not call sk_free() or delete on
88 * the block.
89 */
90template <size_t kSizeRequested> class SkAutoSMalloc : SkNoncopyable {
91public:
92 /**
93 * Creates initially empty storage. get() returns a ptr, but it is to a zero-byte allocation.
94 * Must call reset(size) to return an allocated block.
95 */
97 fPtr = fStorage;
98 fSize = kSize;
99 }
100
101 /**
102 * Allocate a block of the specified size. If size <= kSizeRequested (or slightly more), then
103 * the allocation will come from the stack, otherwise it will be dynamically allocated.
104 */
105 explicit SkAutoSMalloc(size_t size) {
106 fPtr = fStorage;
107 fSize = kSize;
108 this->reset(size);
109 }
110
111 /**
112 * Free the allocated block (if any). If the block was small enough to have been allocated on
113 * the stack, then this does nothing.
114 */
116 if (fPtr != (void*)fStorage) {
117 sk_free(fPtr);
118 }
119 }
120
121 /**
122 * Return the allocated block. May return non-null even if the block is of zero size. Since
123 * this may be on the stack or dynamically allocated, the caller must not call sk_free() on it,
124 * but must rely on SkAutoSMalloc to manage it.
125 */
126 void* get() const { return fPtr; }
127
128 /**
129 * Return a new block of the requested size, freeing (as necessary) any previously allocated
130 * block. As with the constructor, if size <= kSizeRequested (or slightly more) then the return
131 * block may be allocated locally, rather than from the heap.
132 */
133 void* reset(size_t size,
135 bool* didChangeAlloc = nullptr) {
136 size = (size < kSize) ? kSize : size;
137 bool alloc = size != fSize && (SkAutoMalloc::kAlloc_OnShrink == shrink || size > fSize);
138 if (didChangeAlloc) {
139 *didChangeAlloc = alloc;
140 }
141 if (alloc) {
142 if (fPtr != (void*)fStorage) {
143 sk_free(fPtr);
144 }
145
146 if (size == kSize) {
147 SkASSERT(fPtr != fStorage); // otherwise we lied when setting didChangeAlloc.
148 fPtr = fStorage;
149 } else {
150 fPtr = sk_malloc_throw(size);
151 }
152
153 fSize = size;
154 }
155 SkASSERT(fSize >= size && fSize >= kSize);
156 SkASSERT((fPtr == fStorage) || fSize > kSize);
157 return fPtr;
158 }
159
160private:
161 // Align up to 32 bits.
162 static const size_t kSizeAlign4 = SkAlign4(kSizeRequested);
163#if defined(SK_BUILD_FOR_GOOGLE3)
164 // Stack frame size is limited for SK_BUILD_FOR_GOOGLE3. 4k is less than the actual max, but some functions
165 // have multiple large stack allocations.
166 static const size_t kMaxBytes = 4 * 1024;
167 static const size_t kSize = kSizeRequested > kMaxBytes ? kMaxBytes : kSizeAlign4;
168#else
169 static const size_t kSize = kSizeAlign4;
170#endif
171
172 void* fPtr;
173 size_t fSize; // can be larger than the requested size (see kReuse)
174 uint32_t fStorage[kSize >> 2];
175};
176// Can't guard the constructor because it's a template class.
177
178#endif
m reset()
static constexpr T SkAlign4(T x)
Definition SkAlign.h:16
#define SkASSERT(cond)
Definition SkAssert.h:116
SK_API void sk_free(void *)
static void * sk_malloc_throw(size_t size)
Definition SkMalloc.h:67
void * release()
const void * get() const
void * reset(size_t size=0, OnShrink shrink=kAlloc_OnShrink)
void * get()
SkAutoMalloc(size_t size=0)
SkAutoSMalloc(size_t size)
void * get() const
void * reset(size_t size, SkAutoMalloc::OnShrink shrink=SkAutoMalloc::kAlloc_OnShrink, bool *didChangeAlloc=nullptr)