in folly/compression/Compression.cpp [235:295]
bool StreamCodec::compressStream(
ByteRange& input, MutableByteRange& output, StreamCodec::FlushOp flushOp) {
if (state_ == State::RESET && input.empty() &&
flushOp == StreamCodec::FlushOp::END &&
uncompressedLength().value_or(0) != 0) {
throw std::runtime_error("Codec: invalid uncompressed length");
}
if (!uncompressedLength() && needsDataLength()) {
throw std::runtime_error("Codec: uncompressed length required");
}
if (state_ == State::RESET && !input.empty() &&
uncompressedLength() == uint64_t(0)) {
throw std::runtime_error("Codec: invalid uncompressed length");
}
// Handle input state transitions
switch (flushOp) {
case StreamCodec::FlushOp::NONE:
if (state_ == State::RESET) {
state_ = State::COMPRESS;
}
assertStateIs(State::COMPRESS);
break;
case StreamCodec::FlushOp::FLUSH:
if (state_ == State::RESET || state_ == State::COMPRESS) {
state_ = State::COMPRESS_FLUSH;
}
assertStateIs(State::COMPRESS_FLUSH);
break;
case StreamCodec::FlushOp::END:
if (state_ == State::RESET || state_ == State::COMPRESS) {
state_ = State::COMPRESS_END;
}
assertStateIs(State::COMPRESS_END);
break;
}
size_t const inputSize = input.size();
size_t const outputSize = output.size();
bool const done = doCompressStream(input, output, flushOp);
if (!done && inputSize == input.size() && outputSize == output.size()) {
if (!progressMade_) {
throw std::runtime_error("Codec: No forward progress made");
}
// Throw an exception if there is no progress again next time
progressMade_ = false;
} else {
progressMade_ = true;
}
// Handle output state transitions
if (done) {
if (state_ == State::COMPRESS_FLUSH) {
state_ = State::COMPRESS;
} else if (state_ == State::COMPRESS_END) {
state_ = State::END;
}
// Check internal invariants
DCHECK(input.empty());
DCHECK(flushOp != StreamCodec::FlushOp::NONE);
}
return done;
}