| // Copyright 2019 Google LLC. | |
| // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. | |
| #include "include/private/base/SkContainers.h" | |
| #include "include/private/base/SkAlign.h" | |
| #include "include/private/base/SkAssert.h" | |
| #include "include/private/base/SkMalloc.h" | |
| #include "include/private/base/SkTo.h" | |
| #include <algorithm> | |
| #include <cstddef> | |
| namespace { | |
| // Return at least as many bytes to keep malloc aligned. | |
| constexpr size_t kMinBytes = alignof(max_align_t); | |
| SkSpan<std::byte> complete_size(void* ptr, size_t size) { | |
| if (ptr == nullptr) { | |
| return {}; | |
| } | |
| return {static_cast<std::byte*>(ptr), sk_malloc_size(ptr, size)}; | |
| } | |
| } // namespace | |
| SkSpan<std::byte> SkContainerAllocator::allocate(int capacity, double growthFactor) { | |
| SkASSERT(capacity >= 0); | |
| SkASSERT(growthFactor >= 1.0); | |
| SkASSERT_RELEASE(capacity <= fMaxCapacity); | |
| if (growthFactor > 1.0 && capacity > 0) { | |
| capacity = this->growthFactorCapacity(capacity, growthFactor); | |
| } | |
| return sk_allocate_throw(capacity * fSizeOfT); | |
| } | |
| size_t SkContainerAllocator::roundUpCapacity(int64_t capacity) const { | |
| SkASSERT(capacity >= 0); | |
| // If round will not go above fMaxCapacity return rounded capacity. | |
| if (capacity < fMaxCapacity - kCapacityMultiple) { | |
| return SkAlignTo(capacity, kCapacityMultiple); | |
| } | |
| return SkToSizeT(fMaxCapacity); | |
| } | |
| size_t SkContainerAllocator::growthFactorCapacity(int capacity, double growthFactor) const { | |
| SkASSERT(capacity >= 0); | |
| SkASSERT(growthFactor >= 1.0); | |
| // Multiply by the growthFactor. Remember this must be done in 64-bit ints and not | |
| // size_t because size_t changes. | |
| const int64_t capacityGrowth = static_cast<int64_t>(capacity * growthFactor); | |
| // Notice that for small values of capacity, rounding up will provide most of the growth. | |
| return this->roundUpCapacity(capacityGrowth); | |
| } | |
| SkSpan<std::byte> sk_allocate_canfail(size_t size) { | |
| // Make sure to ask for at least the minimum number of bytes. | |
| const size_t adjustedSize = std::max(size, kMinBytes); | |
| void* ptr = sk_malloc_canfail(adjustedSize); | |
| return complete_size(ptr, adjustedSize); | |
| } | |
| SkSpan<std::byte> sk_allocate_throw(size_t size) { | |
| if (size == 0) { | |
| return {}; | |
| } | |
| // Make sure to ask for at least the minimum number of bytes. | |
| const size_t adjustedSize = std::max(size, kMinBytes); | |
| void* ptr = sk_malloc_throw(adjustedSize); | |
| return complete_size(ptr, adjustedSize); | |
| } | |
| void sk_report_container_overflow_and_die() { | |
| SK_ABORT("Requested capacity is too large."); | |
| } |