void IOBuf::unshareOneSlow() { // Allocate a new buffer for the data uint8_t* buf; SharedInfo* sharedInfo; uint64_t actualCapacity; allocExtBuffer(capacity_, &buf, &sharedInfo, &actualCapacity); // Copy the data // Maintain the same amount of headroom. Since we maintained the same // minimum capacity we also maintain at least the same amount of tailroom. uint64_t headlen = headroom(); if (length_ > 0) { assert(data_ != nullptr); memcpy(buf + headlen, data_, length_); } // Release our reference on the old buffer decrementRefcount(); // Make sure kFlagMaybeShared and kFlagFreeSharedInfo are all cleared. setFlagsAndSharedInfo(0, sharedInfo); // Update the buffer pointers to point to the new buffer data_ = buf + headlen; buf_ = buf; }
IOBuf::~IOBuf() { // Destroying an IOBuf destroys the entire chain. // Users of IOBuf should only explicitly delete the head of any chain. // The other elements in the chain will be automatically destroyed. while (next_ != this) { // Since unlink() returns unique_ptr() and we don't store it, // it will automatically delete the unlinked element. (void)next_->unlink(); } decrementRefcount(); }
void IOBuf::coalesceAndReallocate(size_t newHeadroom, size_t newLength, IOBuf* end, size_t newTailroom) { uint64_t newCapacity = newLength + newHeadroom + newTailroom; if (newCapacity > UINT32_MAX) { throw std::overflow_error("IOBuf chain too large to coalesce"); } // Allocate space for the coalesced buffer. // We always convert to an external buffer, even if we happened to be an // internal buffer before. uint8_t* newBuf; SharedInfo* newInfo; uint32_t actualCapacity; allocExtBuffer(newCapacity, &newBuf, &newInfo, &actualCapacity); // Copy the data into the new buffer uint8_t* newData = newBuf + newHeadroom; uint8_t* p = newData; IOBuf* current = this; size_t remaining = newLength; do { assert(current->length_ <= remaining); remaining -= current->length_; memcpy(p, current->data_, current->length_); p += current->length_; current = current->next_; } while (current != end); assert(remaining == 0); // Point at the new buffer decrementRefcount(); // Make sure kFlagUserOwned, kFlagMaybeShared, and kFlagFreeSharedInfo // are all cleared. flags_ = 0; capacity_ = actualCapacity; type_ = kExtAllocated; buf_ = newBuf; sharedInfo_ = newInfo; data_ = newData; length_ = newLength; // Separate from the rest of our chain. // Since we don't store the unique_ptr returned by separateChain(), // this will immediately delete the returned subchain. if (isChained()) { (void)separateChain(next_, current->prev_); } }
void IOBuf::coalesceAndReallocate(size_t newHeadroom, size_t newLength, IOBuf* end, size_t newTailroom) { uint64_t newCapacity = newLength + newHeadroom + newTailroom; // Allocate space for the coalesced buffer. // We always convert to an external buffer, even if we happened to be an // internal buffer before. uint8_t* newBuf; SharedInfo* newInfo; uint64_t actualCapacity; allocExtBuffer(newCapacity, &newBuf, &newInfo, &actualCapacity); // Copy the data into the new buffer uint8_t* newData = newBuf + newHeadroom; uint8_t* p = newData; IOBuf* current = this; size_t remaining = newLength; do { if (current->length_ > 0) { assert(current->length_ <= remaining); assert(current->data_ != nullptr); remaining -= current->length_; memcpy(p, current->data_, current->length_); p += current->length_; } current = current->next_; } while (current != end); assert(remaining == 0); // Point at the new buffer decrementRefcount(); // Make sure kFlagMaybeShared and kFlagFreeSharedInfo are all cleared. setFlagsAndSharedInfo(0, newInfo); capacity_ = actualCapacity; buf_ = newBuf; data_ = newData; length_ = newLength; // Separate from the rest of our chain. // Since we don't store the unique_ptr returned by separateChain(), // this will immediately delete the returned subchain. if (isChained()) { (void)separateChain(next_, current->prev_); } }
IOBuf& IOBuf::operator=(IOBuf&& other) noexcept { // If we are part of a chain, delete the rest of the chain. while (next_ != this) { // Since unlink() returns unique_ptr() and we don't store it, // it will automatically delete the unlinked element. (void)next_->unlink(); } // Decrement our refcount on the current buffer decrementRefcount(); // Take ownership of the other buffer's data data_ = other.data_; buf_ = other.buf_; length_ = other.length_; capacity_ = other.capacity_; flags_ = other.flags_; type_ = other.type_; sharedInfo_ = other.sharedInfo_; // Reset other so it is a clean state to be destroyed. other.data_ = nullptr; other.buf_ = nullptr; other.length_ = 0; other.capacity_ = 0; other.flags_ = kFlagUserOwned; other.type_ = kExtUserOwned; other.sharedInfo_ = nullptr; // If other was part of the chain, assume ownership of the rest of its chain. // (It's only valid to perform move assignment on the head of a chain.) if (other.next_ != &other) { next_ = other.next_; next_->prev_ = this; other.next_ = &other; prev_ = other.prev_; prev_->next_ = this; other.prev_ = &other; } // Sanity check to make sure that other is in a valid state to be destroyed. DCHECK_EQ(other.prev_, &other); DCHECK_EQ(other.next_, &other); DCHECK(other.flags_ & kFlagUserOwned); return *this; }
void IOBuf::unshareOneSlow() { // Allocate a new buffer for the data uint8_t* buf; SharedInfo* sharedInfo; uint32_t actualCapacity; allocExtBuffer(capacity_, &buf, &sharedInfo, &actualCapacity); // Copy the data // Maintain the same amount of headroom. Since we maintained the same // minimum capacity we also maintain at least the same amount of tailroom. uint32_t headlen = headroom(); memcpy(buf + headlen, data_, length_); // Release our reference on the old buffer decrementRefcount(); // Make sure kFlagUserOwned, kFlagMaybeShared, and kFlagFreeSharedInfo // are all cleared. flags_ = 0; // Update the buffer pointers to point to the new buffer data_ = buf + headlen; buf_ = buf; sharedInfo_ = sharedInfo; }
void ResourceCache::decrementRefcount(const Res_png_9patch* patchResource) { decrementRefcount((void*) patchResource); }
void ResourceCache::decrementRefcount(const SkPath* pathResource) { decrementRefcount((void*) pathResource); }
void ResourceCache::decrementRefcount(const SkBitmap* bitmapResource) { decrementRefcount((void*) bitmapResource); }
void ResourceCache::decrementRefcount(Layer* layerResource) { decrementRefcount((void*) layerResource); }
void ResourceCache::decrementRefcount(SkiaColorFilter* filterResource) { SkSafeUnref(filterResource->getSkColorFilter()); decrementRefcount((void*) filterResource); }
void ResourceCache::decrementRefcount(SkiaShader* shaderResource) { SkSafeUnref(shaderResource->getSkShader()); decrementRefcount((void*) shaderResource); }
void ResourceCache::decrementRefcount(SkBitmap* bitmapResource) { bitmapResource->pixelRef()->globalUnref(); SkSafeUnref(bitmapResource->getColorTable()); decrementRefcount((void*) bitmapResource); }