blob: aeac67a475969731f8d4222eec1c1898abd6718f [file] [log] [blame]
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/private/SkTDArray.h"
#include "include/private/SkTo.h"
SkTDStorage::SkTDStorage(SkTDStorage&& that)
: fStorage{std::move(that.fStorage)} { that.fStorage = nullptr; }
SkTDStorage& SkTDStorage::operator=(SkTDStorage&& that) {
if (this != &that) {
this->~SkTDStorage();
new (this) SkTDStorage{std::move(that)};
}
return *this;
}
SkTDStorage::~SkTDStorage() {
sk_free(fStorage);
}
int SkTDStorage::assign(const void* src, int count, size_t sizeOfT) {
if (count > 0) {
fStorage = sk_realloc_throw(fStorage, SkToSizeT(count) * sizeOfT);
memcpy(fStorage, src, SkToSizeT(count) * sizeOfT);
}
return count;
}
int SkTDStorage::resizeStorageToAtLeast(int count, size_t sizeOfT) {
SkASSERT(count > 0);
// Establish the maximum number of elements that includes a valid count for end. In the
// largest case end() = &fArray[INT_MAX] which is 1 after the last indexable element.
static constexpr int kMaxCount = INT_MAX;
// Assume that the array will max out.
int newReserve = kMaxCount;
if (kMaxCount - count > 4) {
// Add 1/4 more than we need. Add 4 to ensure this grows by at least 1. Pin to
// kMaxCount if no room for 1/4 growth.
int growth = 4 + ((count + 4) >> 2);
// Read this line as: if (count + growth < kMaxCount) { ... }
// It's rewritten to avoid signed integer overflow.
if (kMaxCount - count > growth) {
newReserve = count + growth;
}
}
fStorage = sk_realloc_throw(fStorage, SkToSizeT(newReserve) * sizeOfT);
return newReserve;
}
int SkTDStorage::shrinkToFit(int count, size_t sizeOfT) {
fStorage = sk_realloc_throw(fStorage, SkToSizeT(count) * sizeOfT);
return count;
}
SkTDStorage::StateUpdate SkTDStorage::append(
const void* src, int count, size_t sizeOfT, int reserve, int oldCount) {
SkASSERT(count >= 0);
int newCount = oldCount;
int newReserve = reserve;
if (count > 0) {
// We take care to avoid overflow here.
// The sum of fCount and delta is at most 4294967294, which fits fine in uint32_t.
uint32_t testCount = (uint32_t)oldCount + (uint32_t)count;
SkASSERT_RELEASE(SkTFitsIn<int>(testCount));
newCount = testCount;
if (newCount > reserve) {
newReserve = this->resizeStorageToAtLeast(newCount, sizeOfT);
}
if (src != nullptr) {
memcpy(this->data<char>() + sizeOfT *SkToSizeT(oldCount), src,
sizeOfT *SkToSizeT(count));
}
}
return {newCount, newReserve};
}