// 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/SkFeatures.h" #include "include/private/base/SkMalloc.h" #include "include/private/base/SkTo.h" #include #include #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) #include #elif defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX) #include #elif defined(SK_BUILD_FOR_WIN) #include #endif namespace { // Return at least as many bytes to keep malloc aligned. constexpr size_t kMinBytes = alignof(max_align_t); SkSpan complete_size(void* ptr, size_t size) { if (ptr == nullptr) { return {}; } size_t completeSize = size; // Use the OS specific calls to find the actual capacity. #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) // TODO: remove the max, when the chrome implementation of malloc_size doesn't return 0. completeSize = std::max(malloc_size(ptr), size); #elif defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 17 completeSize = malloc_usable_size(ptr); SkASSERT(completeSize >= size); #elif defined(SK_BUILD_FOR_UNIX) completeSize = malloc_usable_size(ptr); SkASSERT(completeSize >= size); #elif defined(SK_BUILD_FOR_WIN) completeSize = _msize(ptr); SkASSERT(completeSize >= size); #endif return {static_cast(ptr), completeSize}; } } // namespace SkSpan 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(capacity * growthFactor); // Notice that for small values of capacity, rounding up will provide most of the growth. return this->roundUpCapacity(capacityGrowth); } SkSpan 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 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."); }