SkAutoMalloc.h 5.8 KB

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