diff options
author | Hal Canary <halcanary@google.com> | 2017-01-12 13:47:57 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-01-12 19:49:46 +0000 |
commit | 5aedd6d5a31973dcfc8ecb9f995ac0e8d9840163 (patch) | |
tree | 0efc82a25a1ceeb2980ef55e0ecb912a2145d29d /src/core/SkAutoMalloc.h | |
parent | 444c1bd38a99872e977efd30277b59f5402f7087 (diff) |
cleanup after 95e3c05
Change-Id: Ifd194fd009196b8bee2dd83328bbe698586d72f4
Reviewed-on: https://skia-review.googlesource.com/6965
Reviewed-by: Ben Wagner <bungeman@google.com>
Reviewed-by: Hal Canary <halcanary@google.com>
Commit-Queue: Hal Canary <halcanary@google.com>
Commit-Queue: Ben Wagner <bungeman@google.com>
Diffstat (limited to 'src/core/SkAutoMalloc.h')
-rw-r--r-- | src/core/SkAutoMalloc.h | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/src/core/SkAutoMalloc.h b/src/core/SkAutoMalloc.h new file mode 100644 index 0000000000..7be882547d --- /dev/null +++ b/src/core/SkAutoMalloc.h @@ -0,0 +1,174 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkAutoMalloc_DEFINED +#define SkAutoMalloc_DEFINED + +#include "SkTypes.h" + +#include <memory> + +/** + * Manage an allocated block of heap memory. This object is the sole manager of + * the lifetime of the block, so the caller must not call sk_free() or delete + * on the block, unless release() was called. + */ +class SkAutoMalloc : SkNoncopyable { +public: + explicit SkAutoMalloc(size_t size = 0) + : fPtr(size ? sk_malloc_throw(size) : nullptr), fSize(size) {} + + /** + * Passed to reset to specify what happens if the requested size is smaller + * than the current size (and the current block was dynamically allocated). + */ + enum OnShrink { + /** + * If the requested size is smaller than the current size, and the + * current block is dynamically allocated, free the old block and + * malloc a new block of the smaller size. + */ + kAlloc_OnShrink, + + /** + * If the requested size is smaller than the current size, and the + * current block is dynamically allocated, just return the old + * block. + */ + kReuse_OnShrink + }; + + /** + * Reallocates the block to a new size. The ptr may or may not change. + */ + void* reset(size_t size = 0, OnShrink shrink = kAlloc_OnShrink) { + if (size != fSize && (size > fSize || kReuse_OnShrink != shrink)) { + fPtr.reset(size ? sk_malloc_throw(size) : nullptr); + fSize = size; + } + return fPtr.get(); + } + + /** + * Return the allocated block. + */ + void* get() { return fPtr.get(); } + const void* get() const { return fPtr.get(); } + + /** Transfer ownership of the current ptr to the caller, setting the + internal reference to null. Note the caller is reponsible for calling + sk_free on the returned address. + */ + void* release() { + fSize = 0; + return fPtr.release(); + } + +private: + struct WrapFree { + void operator()(void* p) { sk_free(p); } + }; + std::unique_ptr<void, WrapFree> fPtr; + size_t fSize; // can be larger than the requested size (see kReuse) +}; +#define SkAutoMalloc(...) SK_REQUIRE_LOCAL_VAR(SkAutoMalloc) + +/** + * Manage an allocated block of memory. If the requested size is <= kSizeRequested (or slightly + * more), then the allocation will come from the stack rather than the heap. This object is the + * sole manager of the lifetime of the block, so the caller must not call sk_free() or delete on + * the block. + */ +template <size_t kSizeRequested> class SkAutoSMalloc : SkNoncopyable { +public: + /** + * Creates initially empty storage. get() returns a ptr, but it is to a zero-byte allocation. + * Must call reset(size) to return an allocated block. + */ + SkAutoSMalloc() { + fPtr = fStorage; + fSize = kSize; + } + + /** + * Allocate a block of the specified size. If size <= kSizeRequested (or slightly more), then + * the allocation will come from the stack, otherwise it will be dynamically allocated. + */ + explicit SkAutoSMalloc(size_t size) { + fPtr = fStorage; + fSize = kSize; + this->reset(size); + } + + /** + * Free the allocated block (if any). If the block was small enough to have been allocated on + * the stack, then this does nothing. + */ + ~SkAutoSMalloc() { + if (fPtr != (void*)fStorage) { + sk_free(fPtr); + } + } + + /** + * Return the allocated block. May return non-null even if the block is of zero size. Since + * this may be on the stack or dynamically allocated, the caller must not call sk_free() on it, + * but must rely on SkAutoSMalloc to manage it. + */ + void* get() const { return fPtr; } + + /** + * Return a new block of the requested size, freeing (as necessary) any previously allocated + * block. As with the constructor, if size <= kSizeRequested (or slightly more) then the return + * block may be allocated locally, rather than from the heap. + */ + void* reset(size_t size, + SkAutoMalloc::OnShrink shrink = SkAutoMalloc::kAlloc_OnShrink, + bool* didChangeAlloc = nullptr) { + size = (size < kSize) ? kSize : size; + bool alloc = size != fSize && (SkAutoMalloc::kAlloc_OnShrink == shrink || size > fSize); + if (didChangeAlloc) { + *didChangeAlloc = alloc; + } + if (alloc) { + if (fPtr != (void*)fStorage) { + sk_free(fPtr); + } + + if (size == kSize) { + SkASSERT(fPtr != fStorage); // otherwise we lied when setting didChangeAlloc. + fPtr = fStorage; + } else { + fPtr = sk_malloc_flags(size, SK_MALLOC_THROW | SK_MALLOC_TEMP); + } + + fSize = size; + } + SkASSERT(fSize >= size && fSize >= kSize); + SkASSERT((fPtr == fStorage) || fSize > kSize); + return fPtr; + } + +private: + // Align up to 32 bits. + static const size_t kSizeAlign4 = SkAlign4(kSizeRequested); +#if defined(GOOGLE3) + // Stack frame size is limited for GOOGLE3. 4k is less than the actual max, but some functions + // have multiple large stack allocations. + static const size_t kMaxBytes = 4 * 1024; + static const size_t kSize = kSizeRequested > kMaxBytes ? kMaxBytes : kSizeAlign4; +#else + static const size_t kSize = kSizeAlign4; +#endif + + void* fPtr; + size_t fSize; // can be larger than the requested size (see kReuse) + uint32_t fStorage[kSize >> 2]; +}; +// Can't guard the constructor because it's a template class. + +#endif |