18300a3aa7
The C++ standard library uses the name "release" for the operation we call "detach". Rewriting each "detach(" to "release(" brings us a step closer to using standard library types directly (e.g. std::unique_ptr instead of SkAutoTDelete). This was a fairly blind transformation. There may have been unintentional conversions in here, but it's probably for the best to have everything uniformly say "release". BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1809733002 Review URL: https://codereview.chromium.org/1809733002
213 lines
6.8 KiB
C++
213 lines
6.8 KiB
C++
/*
|
|
* Copyright 2013 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include "SkFrontBufferedStream.h"
|
|
#include "SkStream.h"
|
|
#include "SkTemplates.h"
|
|
|
|
class FrontBufferedStream : public SkStreamRewindable {
|
|
public:
|
|
// Called by Create.
|
|
FrontBufferedStream(SkStream*, size_t bufferSize);
|
|
|
|
size_t read(void* buffer, size_t size) override;
|
|
|
|
size_t peek(void* buffer, size_t size) const override;
|
|
|
|
bool isAtEnd() const override;
|
|
|
|
bool rewind() override;
|
|
|
|
bool hasLength() const override { return fHasLength; }
|
|
|
|
size_t getLength() const override { return fLength; }
|
|
|
|
SkStreamRewindable* duplicate() const override { return nullptr; }
|
|
|
|
private:
|
|
SkAutoTDelete<SkStream> fStream;
|
|
const bool fHasLength;
|
|
const size_t fLength;
|
|
// Current offset into the stream. Always >= 0.
|
|
size_t fOffset;
|
|
// Amount that has been buffered by calls to read. Will always be less than
|
|
// fBufferSize.
|
|
size_t fBufferedSoFar;
|
|
// Total size of the buffer.
|
|
const size_t fBufferSize;
|
|
// FIXME: SkAutoTMalloc throws on failure. Instead, Create should return a
|
|
// nullptr stream.
|
|
SkAutoTMalloc<char> fBuffer;
|
|
|
|
// Read up to size bytes from already buffered data, and copy to
|
|
// dst, if non-nullptr. Updates fOffset. Assumes that fOffset is less
|
|
// than fBufferedSoFar.
|
|
size_t readFromBuffer(char* dst, size_t size);
|
|
|
|
// Buffer up to size bytes from the stream, and copy to dst if non-
|
|
// nullptr. Updates fOffset and fBufferedSoFar. Assumes that fOffset is
|
|
// less than fBufferedSoFar, and size is greater than 0.
|
|
size_t bufferAndWriteTo(char* dst, size_t size);
|
|
|
|
// Read up to size bytes directly from the stream and into dst if non-
|
|
// nullptr. Updates fOffset. Assumes fOffset is at or beyond the buffered
|
|
// data, and size is greater than 0.
|
|
size_t readDirectlyFromStream(char* dst, size_t size);
|
|
|
|
typedef SkStream INHERITED;
|
|
};
|
|
|
|
SkStreamRewindable* SkFrontBufferedStream::Create(SkStream* stream, size_t bufferSize) {
|
|
if (nullptr == stream) {
|
|
return nullptr;
|
|
}
|
|
return new FrontBufferedStream(stream, bufferSize);
|
|
}
|
|
|
|
FrontBufferedStream::FrontBufferedStream(SkStream* stream, size_t bufferSize)
|
|
: fStream(stream)
|
|
, fHasLength(stream->hasPosition() && stream->hasLength())
|
|
, fLength(stream->getLength() - stream->getPosition())
|
|
, fOffset(0)
|
|
, fBufferedSoFar(0)
|
|
, fBufferSize(bufferSize)
|
|
, fBuffer(bufferSize) {}
|
|
|
|
bool FrontBufferedStream::isAtEnd() const {
|
|
if (fOffset < fBufferedSoFar) {
|
|
// Even if the underlying stream is at the end, this stream has been
|
|
// rewound after buffering, so it is not at the end.
|
|
return false;
|
|
}
|
|
|
|
return fStream->isAtEnd();
|
|
}
|
|
|
|
bool FrontBufferedStream::rewind() {
|
|
// Only allow a rewind if we have not exceeded the buffer.
|
|
if (fOffset <= fBufferSize) {
|
|
fOffset = 0;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
size_t FrontBufferedStream::readFromBuffer(char* dst, size_t size) {
|
|
SkASSERT(fOffset < fBufferedSoFar);
|
|
// Some data has already been copied to fBuffer. Read up to the
|
|
// lesser of the size requested and the remainder of the buffered
|
|
// data.
|
|
const size_t bytesToCopy = SkTMin(size, fBufferedSoFar - fOffset);
|
|
if (dst != nullptr) {
|
|
memcpy(dst, fBuffer + fOffset, bytesToCopy);
|
|
}
|
|
|
|
// Update fOffset to the new position. It is guaranteed to be
|
|
// within the buffered data.
|
|
fOffset += bytesToCopy;
|
|
SkASSERT(fOffset <= fBufferedSoFar);
|
|
|
|
return bytesToCopy;
|
|
}
|
|
|
|
size_t FrontBufferedStream::bufferAndWriteTo(char* dst, size_t size) {
|
|
SkASSERT(size > 0);
|
|
SkASSERT(fOffset >= fBufferedSoFar);
|
|
SkASSERT(fBuffer);
|
|
// Data needs to be buffered. Buffer up to the lesser of the size requested
|
|
// and the remainder of the max buffer size.
|
|
const size_t bytesToBuffer = SkTMin(size, fBufferSize - fBufferedSoFar);
|
|
char* buffer = fBuffer + fOffset;
|
|
const size_t buffered = fStream->read(buffer, bytesToBuffer);
|
|
|
|
fBufferedSoFar += buffered;
|
|
fOffset = fBufferedSoFar;
|
|
SkASSERT(fBufferedSoFar <= fBufferSize);
|
|
|
|
// Copy the buffer to the destination buffer and update the amount read.
|
|
if (dst != nullptr) {
|
|
memcpy(dst, buffer, buffered);
|
|
}
|
|
|
|
return buffered;
|
|
}
|
|
|
|
size_t FrontBufferedStream::readDirectlyFromStream(char* dst, size_t size) {
|
|
SkASSERT(size > 0);
|
|
// If we get here, we have buffered all that can be buffered.
|
|
SkASSERT(fBufferSize == fBufferedSoFar && fOffset >= fBufferSize);
|
|
|
|
const size_t bytesReadDirectly = fStream->read(dst, size);
|
|
fOffset += bytesReadDirectly;
|
|
|
|
// If we have read past the end of the buffer, rewinding is no longer
|
|
// supported, so we can go ahead and free the memory.
|
|
if (bytesReadDirectly > 0) {
|
|
sk_free(fBuffer.release());
|
|
}
|
|
|
|
return bytesReadDirectly;
|
|
}
|
|
|
|
size_t FrontBufferedStream::peek(void* dst, size_t size) const {
|
|
// Keep track of the offset so we can return to it.
|
|
const size_t start = fOffset;
|
|
|
|
if (start >= fBufferSize) {
|
|
// This stream is not able to buffer.
|
|
return 0;
|
|
}
|
|
|
|
size = SkTMin(size, fBufferSize - start);
|
|
FrontBufferedStream* nonConstThis = const_cast<FrontBufferedStream*>(this);
|
|
const size_t bytesRead = nonConstThis->read(dst, size);
|
|
nonConstThis->fOffset = start;
|
|
return bytesRead;
|
|
}
|
|
|
|
size_t FrontBufferedStream::read(void* voidDst, size_t size) {
|
|
// Cast voidDst to a char* for easy addition.
|
|
char* dst = reinterpret_cast<char*>(voidDst);
|
|
SkDEBUGCODE(const size_t totalSize = size;)
|
|
const size_t start = fOffset;
|
|
|
|
// First, read any data that was previously buffered.
|
|
if (fOffset < fBufferedSoFar) {
|
|
const size_t bytesCopied = this->readFromBuffer(dst, size);
|
|
|
|
// Update the remaining number of bytes needed to read
|
|
// and the destination buffer.
|
|
size -= bytesCopied;
|
|
SkASSERT(size + (fOffset - start) == totalSize);
|
|
if (dst != nullptr) {
|
|
dst += bytesCopied;
|
|
}
|
|
}
|
|
|
|
// Buffer any more data that should be buffered, and copy it to the
|
|
// destination.
|
|
if (size > 0 && fBufferedSoFar < fBufferSize && !fStream->isAtEnd()) {
|
|
const size_t buffered = this->bufferAndWriteTo(dst, size);
|
|
|
|
// Update the remaining number of bytes needed to read
|
|
// and the destination buffer.
|
|
size -= buffered;
|
|
SkASSERT(size + (fOffset - start) == totalSize);
|
|
if (dst != nullptr) {
|
|
dst += buffered;
|
|
}
|
|
}
|
|
|
|
if (size > 0 && !fStream->isAtEnd()) {
|
|
SkDEBUGCODE(const size_t bytesReadDirectly =) this->readDirectlyFromStream(dst, size);
|
|
SkDEBUGCODE(size -= bytesReadDirectly;)
|
|
SkASSERT(size + (fOffset - start) == totalSize);
|
|
}
|
|
|
|
return fOffset - start;
|
|
}
|