thrift/lib/cpp2/protocol/CompactProtocol-inl.h (706 lines of code) (raw):
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef THRIFT2_PROTOCOL_COMPACTPROTOCOL_TCC_
#define THRIFT2_PROTOCOL_COMPACTPROTOCOL_TCC_ 1
#include <thrift/lib/cpp2/protocol/CompactProtocol.h>
#include <limits>
#include <thrift/lib/cpp/util/VarintUtils.h>
namespace apache {
namespace thrift {
namespace detail {
namespace compact {
enum Types {
CT_STOP = 0x00,
CT_BOOLEAN_TRUE = 0x01,
CT_BOOLEAN_FALSE = 0x02,
CT_BYTE = 0x03,
CT_I16 = 0x04,
CT_I32 = 0x05,
CT_I64 = 0x06,
CT_DOUBLE = 0x07,
CT_BINARY = 0x08,
CT_LIST = 0x09,
CT_SET = 0x0A,
CT_MAP = 0x0B,
CT_STRUCT = 0x0C,
CT_FLOAT = 0x0D,
};
const int8_t TTypeToCType[20] = {
CT_STOP, // T_STOP
0, // unused
CT_BOOLEAN_TRUE, // T_BOOL
CT_BYTE, // T_BYTE
CT_DOUBLE, // T_DOUBLE
0, // unused
CT_I16, // T_I16
0, // unused
CT_I32, // T_I32
0, // unused
CT_I64, // T_I64
CT_BINARY, // T_STRING
CT_STRUCT, // T_STRUCT
CT_MAP, // T_MAP
CT_SET, // T_SET
CT_LIST, // T_LIST
0, // unused
0, // unused
0, // unused
CT_FLOAT, // T_FLOAT
};
const TType CTypeToTType[14] = {
TType::T_STOP, // CT_STOP
TType::T_BOOL, // CT_BOOLEAN_TRUE
TType::T_BOOL, // CT_BOOLEAN_FASLE
TType::T_BYTE, // CT_BYTE
TType::T_I16, // CT_I16
TType::T_I32, // CT_I32
TType::T_I64, // CT_I64
TType::T_DOUBLE, // CT_DOUBLE
TType::T_STRING, // CT_BINARY
TType::T_LIST, // CT_LIST
TType::T_SET, // CT_SET
TType::T_MAP, // CT_MAP
TType::T_STRUCT, // CT_STRUCT
TType::T_FLOAT, // CT_FLOAT
};
} // namespace compact
} // namespace detail
uint32_t CompactProtocolWriter::writeMessageBegin(
folly::StringPiece name, MessageType messageType, int32_t seqid) {
uint32_t wsize = 0;
wsize += writeByte(apache::thrift::detail::compact::PROTOCOL_ID);
wsize += writeByte(folly::to_narrow(
apache::thrift::detail::compact::COMPACT_PROTOCOL_VERSION |
((static_cast<int32_t>(messageType)
<< apache::thrift::detail::compact::TYPE_SHIFT_AMOUNT) &
apache::thrift::detail::compact::TYPE_MASK)));
wsize += apache::thrift::util::writeVarint(out_, seqid);
wsize += writeString(name);
return wsize;
}
uint32_t CompactProtocolWriter::writeMessageEnd() {
return 0;
}
uint32_t CompactProtocolWriter::writeStructBegin(const char* /* name */) {
lastField_.push(lastFieldId_);
lastFieldId_ = 0;
return 0;
}
uint32_t CompactProtocolWriter::writeStructEnd() {
lastFieldId_ = lastField_.top();
lastField_.pop();
return 0;
}
/**
* The workhorse of writeFieldBegin. It has the option of doing a
* 'type override' of the type header. This is used specifically in the
* boolean field case.
*/
uint32_t CompactProtocolWriter::writeFieldBeginInternal(
const char* /*name*/,
const TType fieldType,
const int16_t fieldId,
int8_t typeOverride,
int16_t previousId) {
DCHECK_EQ(previousId, lastFieldId_);
uint32_t wsize = 0;
// if there's a type override, use that.
int8_t typeToWrite =
(typeOverride == -1
? apache::thrift::detail::compact::TTypeToCType[fieldType]
: typeOverride);
// check if we can use delta encoding for the field id
if (fieldId > previousId && fieldId - previousId <= 15) {
// write them together
wsize += writeByte(
static_cast<int8_t>((fieldId - previousId) << 4) | typeToWrite);
} else {
// write them separate
wsize += writeByte(typeToWrite);
wsize += writeI16(fieldId);
}
lastFieldId_ = fieldId;
return wsize;
}
uint32_t CompactProtocolWriter::writeFieldBegin(
const char* name, TType fieldType, int16_t fieldId, int16_t previousId) {
if (fieldType == TType::T_BOOL) {
booleanField_.name = name;
booleanField_.fieldType = fieldType;
booleanField_.fieldId = fieldId;
} else {
return writeFieldBeginInternal(name, fieldType, fieldId, -1, previousId);
}
return 0;
}
uint32_t CompactProtocolWriter::writeFieldEnd() {
return 0;
}
uint32_t CompactProtocolWriter::writeFieldStop() {
return writeByte((int8_t)TType::T_STOP);
}
uint32_t CompactProtocolWriter::writeMapBegin(
const TType keyType, TType valType, uint32_t size) {
uint32_t wsize = 0;
if (size == 0) {
wsize += writeByte(0);
} else {
wsize += apache::thrift::util::writeVarint(out_, size);
wsize += writeByte(
static_cast<int8_t>(
apache::thrift::detail::compact::TTypeToCType[keyType] << 4) |
apache::thrift::detail::compact::TTypeToCType[valType]);
}
return wsize;
}
uint32_t CompactProtocolWriter::writeMapEnd() {
return 0;
}
uint32_t CompactProtocolWriter::writeCollectionBegin(
int8_t elemType, int32_t size) {
uint32_t wsize = 0;
if (size <= 14) {
wsize += writeByte(static_cast<int8_t>(
size << 4 | apache::thrift::detail::compact::TTypeToCType[elemType]));
} else {
wsize += writeByte(folly::to_narrow(
0xf0 | apache::thrift::detail::compact::TTypeToCType[elemType]));
wsize += apache::thrift::util::writeVarint(out_, size);
}
return wsize;
}
uint32_t CompactProtocolWriter::writeListBegin(TType elemType, uint32_t size) {
return writeCollectionBegin(elemType, size);
}
uint32_t CompactProtocolWriter::writeListEnd() {
return 0;
}
uint32_t CompactProtocolWriter::writeSetBegin(TType elemType, uint32_t size) {
return writeCollectionBegin(elemType, size);
}
uint32_t CompactProtocolWriter::writeSetEnd() {
return 0;
}
uint32_t CompactProtocolWriter::writeBool(bool value) {
uint32_t wsize = 0;
value = detail::validate_bool(value);
if (booleanField_.name != nullptr) {
// we haven't written the field header yet
wsize += writeFieldBeginInternal(
booleanField_.name,
booleanField_.fieldType,
booleanField_.fieldId,
value ? apache::thrift::detail::compact::CT_BOOLEAN_TRUE
: apache::thrift::detail::compact::CT_BOOLEAN_FALSE,
lastFieldId_);
booleanField_.name = nullptr;
} else {
// we're not part of a field, so just write the value
wsize += writeByte(
value ? apache::thrift::detail::compact::CT_BOOLEAN_TRUE
: apache::thrift::detail::compact::CT_BOOLEAN_FALSE);
}
return wsize;
}
uint32_t CompactProtocolWriter::writeByte(int8_t byte) {
out_.write(byte);
return 1;
}
uint32_t CompactProtocolWriter::writeI16(int16_t i16) {
uint32_t sz = apache::thrift::util::writeVarint(
out_, apache::thrift::util::i32ToZigzag(i16));
return sz;
}
uint32_t CompactProtocolWriter::writeI32(int32_t i32) {
uint32_t sz = apache::thrift::util::writeVarint(
out_, apache::thrift::util::i32ToZigzag(i32));
return sz;
}
uint32_t CompactProtocolWriter::writeI64(int64_t i64) {
return apache::thrift::util::writeVarint(
out_, apache::thrift::util::i64ToZigzag(i64));
}
uint32_t CompactProtocolWriter::writeDouble(double dub) {
static_assert(sizeof(double) == sizeof(uint64_t), "");
static_assert(std::numeric_limits<double>::is_iec559, "");
uint64_t bits = folly::bit_cast<uint64_t>(dub);
out_.writeBE(bits);
return sizeof(bits);
}
uint32_t CompactProtocolWriter::writeFloat(float flt) {
static_assert(sizeof(float) == sizeof(uint32_t), "");
static_assert(std::numeric_limits<float>::is_iec559, "");
uint32_t bits = folly::bit_cast<uint32_t>(flt);
out_.writeBE(bits);
return sizeof(bits);
}
uint32_t CompactProtocolWriter::writeString(folly::StringPiece str) {
return writeBinary(str);
}
uint32_t CompactProtocolWriter::writeBinary(folly::StringPiece str) {
return writeBinary(folly::ByteRange(str));
}
uint32_t CompactProtocolWriter::writeBinary(folly::ByteRange str) {
uint32_t size = folly::to_narrow(str.size());
uint32_t result = apache::thrift::util::writeVarint(out_, (int32_t)size);
out_.push(str.data(), size);
return result + size;
}
uint32_t CompactProtocolWriter::writeBinary(
const std::unique_ptr<folly::IOBuf>& str) {
if (!str) {
return writeI32(0);
}
return writeBinary(*str);
}
uint32_t CompactProtocolWriter::writeBinary(const folly::IOBuf& str) {
return writeBinaryImpl<true>(str);
}
uint32_t CompactProtocolWriter::writeRaw(const folly::IOBuf& str) {
return writeBinaryImpl<false>(str);
}
template <bool kWriteSize>
uint32_t CompactProtocolWriter::writeBinaryImpl(const folly::IOBuf& str) {
size_t size = str.computeChainDataLength();
// leave room for varint size
uint32_t limit = std::numeric_limits<uint32_t>::max() - serializedSizeI32();
if (size > limit) {
TProtocolException::throwExceededSizeLimit(size, limit);
}
uint32_t result =
kWriteSize ? apache::thrift::util::writeVarint(out_, (int32_t)size) : 0;
if (sharing_ != SHARE_EXTERNAL_BUFFER && !str.isManaged()) {
const auto growth = size - out_.length();
for (folly::ByteRange buf : str) {
const auto tailroom = out_.length();
if (tailroom < buf.size()) {
out_.push(buf.uncheckedSubpiece(0, tailroom));
buf.uncheckedAdvance(tailroom);
out_.ensure(growth);
}
out_.push(buf);
}
} else {
out_.insert(str);
}
return result + static_cast<uint32_t>(size);
}
void CompactProtocolWriter::rewriteDouble(double dub, int64_t offset) {
auto cursor = RWCursor(out_);
cursor.advanceToEnd();
cursor -= offset;
cursor.writeBE(folly::bit_cast<uint64_t>(dub));
}
folly::io::Cursor CompactProtocolWriter::tail(size_t n) {
auto cursor = RWCursor(out_);
cursor.advanceToEnd();
return {cursor - n, n};
}
/**
* Functions that return the serialized size
*/
uint32_t CompactProtocolWriter::serializedMessageSize(
folly::StringPiece name) const {
// I32{version} + String{name} + I32{seqid}
return 2 * serializedSizeI32() + serializedSizeString(name);
}
uint32_t CompactProtocolWriter::serializedFieldSize(
const char* /*name*/, TType /*fieldType*/, int16_t /*fieldId*/) const {
// byte + I16
return serializedSizeByte() + serializedSizeI16();
}
uint32_t CompactProtocolWriter::serializedStructSize(
const char* /*name*/) const {
return 0;
}
uint32_t CompactProtocolWriter::serializedSizeMapBegin(
TType /*keyType*/, TType /*valType*/, uint32_t /*size*/) const {
return serializedSizeByte() + serializedSizeByte() + serializedSizeI32();
}
uint32_t CompactProtocolWriter::serializedSizeMapEnd() const {
return 0;
}
uint32_t CompactProtocolWriter::serializedSizeListBegin(
TType /*elemType*/, uint32_t /*size*/) const {
return serializedSizeByte() + serializedSizeI32();
}
uint32_t CompactProtocolWriter::serializedSizeListEnd() const {
return 0;
}
uint32_t CompactProtocolWriter::serializedSizeSetBegin(
TType /*elemType*/, uint32_t /*size*/) const {
return serializedSizeByte() + serializedSizeI32();
}
uint32_t CompactProtocolWriter::serializedSizeSetEnd() const {
return 0;
}
uint32_t CompactProtocolWriter::serializedSizeStop() const {
return 1;
}
uint32_t CompactProtocolWriter::serializedSizeBool(bool /* val */) const {
return 1;
}
uint32_t CompactProtocolWriter::serializedSizeByte(int8_t /* val */) const {
return 1;
}
// Varint writes can be up to one additional byte
uint32_t CompactProtocolWriter::serializedSizeI16(int16_t /*val*/) const {
return 3;
}
uint32_t CompactProtocolWriter::serializedSizeI32(int32_t /*val*/) const {
return 5;
}
uint32_t CompactProtocolWriter::serializedSizeI64(int64_t /*val*/) const {
return 10;
}
uint32_t CompactProtocolWriter::serializedSizeDouble(double /*val*/) const {
return 8;
}
uint32_t CompactProtocolWriter::serializedSizeFloat(float /*val*/) const {
return 4;
}
uint32_t CompactProtocolWriter::serializedSizeString(
folly::StringPiece str) const {
return serializedSizeBinary(str);
}
uint32_t CompactProtocolWriter::serializedSizeBinary(
folly::StringPiece str) const {
return serializedSizeBinary(folly::ByteRange(str));
}
uint32_t CompactProtocolWriter::serializedSizeBinary(folly::ByteRange v) const {
// I32{length of string} + binary{string contents}
return serializedSizeI32() + static_cast<uint32_t>(v.size());
}
uint32_t CompactProtocolWriter::serializedSizeBinary(
std::unique_ptr<folly::IOBuf> const& v) const {
return v ? serializedSizeBinary(*v) : 0;
}
uint32_t CompactProtocolWriter::serializedSizeBinary(
folly::IOBuf const& v) const {
size_t size = v.computeChainDataLength();
uint32_t limit = std::numeric_limits<uint32_t>::max() - serializedSizeI32();
if (size > limit) {
TProtocolException::throwExceededSizeLimit(size, limit);
}
return serializedSizeI32() + static_cast<uint32_t>(size);
}
uint32_t CompactProtocolWriter::serializedSizeZCBinary(
folly::StringPiece str) const {
return serializedSizeZCBinary(folly::ByteRange(str));
}
uint32_t CompactProtocolWriter::serializedSizeZCBinary(
folly::ByteRange v) const {
return serializedSizeBinary(v);
}
uint32_t CompactProtocolWriter::serializedSizeZCBinary(
std::unique_ptr<IOBuf> const& v) const {
return v ? serializedSizeZCBinary(*v) : 0;
}
uint32_t CompactProtocolWriter::serializedSizeZCBinary(IOBuf const& v) const {
size_t size = v.computeChainDataLength();
return (size > folly::IOBufQueue::kMaxPackCopy)
? serializedSizeI32() // too big to pack: size only
: static_cast<uint32_t>(size) + serializedSizeI32(); // size + packed data
}
/**
* Reading functions
*/
void CompactProtocolReader::readMessageBegin(
std::string& name, MessageType& messageType, int32_t& seqid) {
int8_t protocolId;
int8_t versionAndType;
readByte(protocolId);
if (protocolId != apache::thrift::detail::compact::PROTOCOL_ID) {
throwBadProtocolIdentifier();
}
readByte(versionAndType);
if ((int8_t)(versionAndType & VERSION_MASK) !=
apache::thrift::detail::compact::COMPACT_PROTOCOL_VERSION) {
throwBadProtocolVersion();
}
messageType =
(MessageType)((uint8_t)(versionAndType & apache::thrift::detail::compact::TYPE_MASK) >> apache::thrift::detail::compact::TYPE_SHIFT_AMOUNT);
apache::thrift::util::readVarint(in_, seqid);
readString(name);
}
void CompactProtocolReader::readMessageEnd() {}
void CompactProtocolReader::readStructBegin(std::string& name) {
if (!name.empty()) {
name.clear();
}
lastField_.push(lastFieldId_);
lastFieldId_ = 0;
}
void CompactProtocolReader::readStructEnd() {
lastFieldId_ = lastField_.top();
lastField_.pop();
}
void CompactProtocolReader::readFieldBegin(
std::string& /*name*/, TType& fieldType, int16_t& fieldId) {
int8_t byte;
int8_t type;
readByte(byte);
type = (byte & 0x0f);
// if it's a stop, then we can return immediately, as the struct is over.
if (type == TType::T_STOP) {
fieldType = TType::T_STOP;
fieldId = 0;
return;
}
// mask off the 4 MSB of the type header. it could contain a field id delta.
int16_t modifier = (int16_t)(((uint8_t)byte & 0xf0) >> 4);
if (modifier == 0) {
// not a delta, look ahead for the zigzag varint field id.
readI16(fieldId);
} else {
fieldId = (int16_t)(lastFieldId_ + modifier);
}
fieldType = getType(type);
// if this happens to be a boolean field, the value is encoded in the type
if (type == apache::thrift::detail::compact::CT_BOOLEAN_TRUE ||
type == apache::thrift::detail::compact::CT_BOOLEAN_FALSE) {
// save the boolean value in a special instance variable.
boolValue_.hasBoolValue = true;
boolValue_.boolValue =
(type == apache::thrift::detail::compact::CT_BOOLEAN_TRUE ? true
: false);
}
// push the new field onto the field stack so we can keep the deltas going.
lastFieldId_ = fieldId;
}
void CompactProtocolReader::readFieldEnd() {}
void CompactProtocolReader::readMapBegin(
TType& keyType, TType& valType, uint32_t& size) {
int8_t kvType = 0;
int32_t msize = 0;
apache::thrift::util::readVarint(in_, msize);
if (msize != 0) {
readByte(kvType);
}
if (msize < 0) {
TProtocolException::throwNegativeSize();
} else if (container_limit_ && msize > container_limit_) {
TProtocolException::throwExceededSizeLimit(msize, container_limit_);
}
keyType = getType((int8_t)((uint8_t)kvType >> 4));
valType = getType((int8_t)((uint8_t)kvType & 0xf));
size = (uint32_t)msize;
}
void CompactProtocolReader::readMapEnd() {}
void CompactProtocolReader::readListBegin(TType& elemType, uint32_t& size) {
int8_t size_and_type;
int32_t lsize;
readByte(size_and_type);
lsize = ((uint8_t)size_and_type >> 4) & 0x0f;
if (lsize == 15) {
apache::thrift::util::readVarint(in_, lsize);
}
if (lsize < 0) {
TProtocolException::throwNegativeSize();
} else if (container_limit_ && lsize > container_limit_) {
TProtocolException::throwExceededSizeLimit(lsize, container_limit_);
}
elemType = getType((int8_t)(size_and_type & 0x0f));
size = (uint32_t)lsize;
}
void CompactProtocolReader::readListEnd() {}
void CompactProtocolReader::readSetBegin(TType& elemType, uint32_t& size) {
readListBegin(elemType, size);
}
void CompactProtocolReader::readSetEnd() {}
void CompactProtocolReader::readBool(bool& value) {
if (boolValue_.hasBoolValue == true) {
value = boolValue_.boolValue;
boolValue_.hasBoolValue = false;
} else {
int8_t val;
readByte(val);
value = (val == apache::thrift::detail::compact::CT_BOOLEAN_TRUE);
}
}
void CompactProtocolReader::readBool(std::vector<bool>::reference value) {
bool ret = false;
readBool(ret);
value = ret;
}
void CompactProtocolReader::readByte(int8_t& byte) {
byte = in_.read<int8_t>();
}
void CompactProtocolReader::readI16(int16_t& i16) {
int32_t value;
apache::thrift::util::readVarint(in_, value);
i16 = (int16_t)apache::thrift::util::zigzagToI32(value);
}
void CompactProtocolReader::readI32(int32_t& i32) {
int32_t value;
apache::thrift::util::readVarint(in_, value);
i32 = apache::thrift::util::zigzagToI32(value);
}
void CompactProtocolReader::readI64(int64_t& i64) {
uint64_t value;
apache::thrift::util::readVarint(in_, value);
i64 = apache::thrift::util::zigzagToI64(value);
}
void CompactProtocolReader::readDouble(double& dub) {
static_assert(sizeof(double) == sizeof(uint64_t), "");
static_assert(std::numeric_limits<double>::is_iec559, "");
uint64_t bits = in_.readBE<int64_t>();
dub = folly::bit_cast<double>(bits);
}
void CompactProtocolReader::readFloat(float& flt) {
static_assert(sizeof(float) == sizeof(uint32_t), "");
static_assert(std::numeric_limits<float>::is_iec559, "");
uint32_t bits = in_.readBE<int32_t>();
flt = folly::bit_cast<float>(bits);
}
void CompactProtocolReader::readStringSize(int32_t& size) {
apache::thrift::util::readVarint(in_, size);
// Catch error cases
if (size < 0) {
TProtocolException::throwNegativeSize();
}
if (string_limit_ > 0 && size > string_limit_) {
TProtocolException::throwExceededSizeLimit(size, string_limit_);
}
}
template <typename StrType>
void CompactProtocolReader::readStringBody(StrType& str, int32_t size) {
if (static_cast<int32_t>(in_.length()) < size) {
if (!in_.canAdvance(size)) {
protocol::TProtocolException::throwTruncatedData();
}
str.reserve(size); // only reserve for multi iter case below
}
str.clear();
size_t size_left = size;
while (size_left > 0) {
auto data = in_.peekBytes();
auto data_avail = std::min(data.size(), size_left);
if (data.empty()) {
TProtocolException::throwTruncatedData();
}
str.append((const char*)data.data(), data_avail);
size_left -= data_avail;
in_.skipNoAdvance(data_avail);
}
}
template <typename StrType>
void CompactProtocolReader::readString(StrType& str) {
int32_t size = 0;
readStringSize(size);
readStringBody(str, size);
}
template <class StrType>
void CompactProtocolReader::readBinary(StrType& str) {
readString(str);
}
void CompactProtocolReader::readBinary(std::unique_ptr<folly::IOBuf>& str) {
if (!str) {
str = std::make_unique<folly::IOBuf>();
}
readBinary(*str);
}
void CompactProtocolReader::readBinary(folly::IOBuf& str) {
int32_t size = 0;
readStringSize(size);
in_.clone(str, size);
if (sharing_ != SHARE_EXTERNAL_BUFFER && !str.isManaged()) {
str = str.cloneCoalescedAsValueWithHeadroomTailroom(0, 0);
str.makeManaged();
}
}
TType CompactProtocolReader::getType(int8_t type) {
using apache::thrift::detail::compact::CTypeToTType;
if (LIKELY(
static_cast<uint8_t>(type) <
sizeof(CTypeToTType) / sizeof(*CTypeToTType))) {
return CTypeToTType[type];
}
throwBadType(type);
}
FOLLY_ALWAYS_INLINE bool CompactProtocolReader::matchTypeHeader(
uint8_t byte, TType type, uint8_t diff) {
if (type == TType::T_BOOL) {
if ((byte ==
(apache::thrift::detail::compact::CT_BOOLEAN_TRUE | (diff << 4))) ||
(byte ==
(apache::thrift::detail::compact::CT_BOOLEAN_FALSE | (diff << 4)))) {
boolValue_.hasBoolValue = true;
boolValue_.boolValue = byte & 1;
return true;
}
return false;
} else {
return byte ==
(apache::thrift::detail::compact::TTypeToCType[type] | (diff << 4));
}
}
bool CompactProtocolReader::advanceToNextField(
int16_t currFieldId,
int16_t nextFieldId,
TType nextFieldType,
StructReadState& state) {
if (in_.length()) {
if (nextFieldType == TType::T_STOP) {
if (*in_.data() == TType::T_STOP) {
in_.skipNoAdvance(1);
return true;
}
} else if (nextFieldId > currFieldId && (nextFieldId - currFieldId <= 15)) {
if (matchTypeHeader(
*in_.data(),
nextFieldType,
static_cast<int8_t>(nextFieldId - currFieldId))) {
in_.skipNoAdvance(1);
return true;
}
} else if (matchTypeHeader(*in_.data(), nextFieldType, 0)) {
// In one byte, we can fit values up to 127 (7-bit, due to varint),
// which corresponds to a range [-64; 63] with zigzag encoding.
// In two bytes, we can fit values up to 16383 (14-bit), which corresponds
// to a range [-8192; 8191] with zigzag encoding.
if (nextFieldId >= -64 && nextFieldId <= 63) {
if (in_.length() > 1 &&
*(in_.data() + 1) ==
static_cast<uint8_t>(util::i32ToZigzag(nextFieldId))) {
in_.skipNoAdvance(2);
return true;
}
} else if (nextFieldId >= -8192 && nextFieldId <= 8191) {
if (in_.length() > 2 &&
*(in_.data() + 1) ==
((util::i32ToZigzag(nextFieldId) & 0x7F) | 0x80) &&
*(in_.data() + 2) ==
((util::i32ToZigzag(nextFieldId) & 0x3F80) >> 7)) {
in_.skipNoAdvance(3);
return true;
}
} else {
if (in_.length() > 3 &&
*(in_.data() + 1) ==
((util::i32ToZigzag(nextFieldId) & 0x7F) | 0x80) &&
*(in_.data() + 2) ==
((util::i32ToZigzag(nextFieldId) & 0x3F80) >> 7 | 0x80) &&
*(in_.data() + 3) ==
((util::i32ToZigzag(nextFieldId) & 0x1FC000) >> 14)) {
in_.skipNoAdvance(4);
return true;
}
}
}
readFieldBeginWithStateMediumSlow(state, currFieldId);
} else {
// We're out of luck, fallback to slow path.
state.fieldId = currFieldId;
state.readFieldBeginNoInline(this);
}
return false;
}
void CompactProtocolReader::readStructBeginWithState(
StructReadState& /* state */) {}
void CompactProtocolReader::readFieldBeginWithState(StructReadState& state) {
int8_t byte;
readByte(byte);
readFieldBeginWithStateImpl(state, state.fieldId, byte);
}
FOLLY_ALWAYS_INLINE void CompactProtocolReader::readFieldBeginWithStateImpl(
StructReadState& state, int16_t prevFieldId, uint8_t firstByte) {
if (firstByte == apache::thrift::detail::compact::CT_STOP) {
state.fieldType = TType::T_STOP;
return;
}
int16_t modifier = (firstByte & 0xf0) >> 4;
if (modifier != 0) {
state.fieldId = prevFieldId + modifier;
} else {
// not a delta, look ahead for the zigzag varint field id.
readI16(state.fieldId);
}
uint8_t type = firstByte & 0xf;
state.fieldType = getType(type);
// if this happens to be a boolean field, the value is encoded in the type
if (type == apache::thrift::detail::compact::CT_BOOLEAN_TRUE ||
type == apache::thrift::detail::compact::CT_BOOLEAN_FALSE) {
// save the boolean value in a special instance variable.
boolValue_.hasBoolValue = true;
boolValue_.boolValue =
type == apache::thrift::detail::compact::CT_BOOLEAN_TRUE;
}
}
constexpr std::size_t CompactProtocolReader::fixedSizeInContainer(TType type) {
switch (type) {
case TType::T_BOOL:
case TType::T_BYTE:
return 1;
case TType::T_FLOAT:
return 4;
case TType::T_DOUBLE:
return 8;
default:
return 0;
}
}
} // namespace thrift
} // namespace apache
#endif // #ifndef THRIFT2_PROTOCOL_COMPACTPROTOCOL_TCC_