/* * 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 #include 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 inline 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(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; } inline uint32_t CompactProtocolWriter::writeMessageEnd() { return 0; } inline uint32_t CompactProtocolWriter::writeStructBegin( const char* /* name */) { descend(); lastField_.push(lastFieldId_); lastFieldId_ = 0; return 0; } inline uint32_t CompactProtocolWriter::writeStructEnd() { lastFieldId_ = lastField_.top(); lastField_.pop(); ascend(); 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. */ inline 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((fieldId - previousId) << 4) | typeToWrite); } else { // write them separate wsize += writeByte(typeToWrite); wsize += writeI16(fieldId); } lastFieldId_ = fieldId; return wsize; } FOLLY_ALWAYS_INLINE 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; } inline uint32_t CompactProtocolWriter::writeFieldEnd() { return 0; } inline uint32_t CompactProtocolWriter::writeFieldStop() { return writeByte((int8_t)TType::T_STOP); } inline uint32_t CompactProtocolWriter::writeMapBegin( const TType keyType, TType valType, uint32_t size) { descend(); uint32_t wsize = 0; if (size == 0) { wsize += writeByte(0); } else { wsize += apache::thrift::util::writeVarint(out_, size); wsize += writeByte( static_cast( apache::thrift::detail::compact::TTypeToCType[keyType] << 4) | apache::thrift::detail::compact::TTypeToCType[valType]); } return wsize; } inline uint32_t CompactProtocolWriter::writeMapEnd() { ascend(); return 0; } inline uint32_t CompactProtocolWriter::writeCollectionBegin( int8_t elemType, int32_t size) { uint32_t wsize = 0; if (size <= 14) { wsize += writeByte(static_cast( 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; } inline uint32_t CompactProtocolWriter::writeListBegin( TType elemType, uint32_t size) { descend(); return writeCollectionBegin(elemType, size); } inline uint32_t CompactProtocolWriter::writeListEnd() { ascend(); return 0; } inline uint32_t CompactProtocolWriter::writeSetBegin( TType elemType, uint32_t size) { descend(); return writeCollectionBegin(elemType, size); } inline uint32_t CompactProtocolWriter::writeSetEnd() { ascend(); return 0; } inline 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; } inline uint32_t CompactProtocolWriter::writeByte(int8_t byte) { out_.write(byte); return 1; } inline uint32_t CompactProtocolWriter::writeI16(int16_t i16) { uint32_t sz = apache::thrift::util::writeVarint( out_, apache::thrift::util::i32ToZigzag(i16)); return sz; } inline uint32_t CompactProtocolWriter::writeI32(int32_t i32) { uint32_t sz = apache::thrift::util::writeVarint( out_, apache::thrift::util::i32ToZigzag(i32)); return sz; } inline uint32_t CompactProtocolWriter::writeI64(int64_t i64) { return apache::thrift::util::writeVarint( out_, apache::thrift::util::i64ToZigzag(i64)); } inline uint32_t CompactProtocolWriter::writeDouble(double dub) { static_assert(sizeof(double) == sizeof(uint64_t), ""); static_assert(std::numeric_limits::is_iec559, ""); uint64_t bits = folly::bit_cast(dub); out_.writeBE(bits); return sizeof(bits); } inline uint32_t CompactProtocolWriter::writeFloat(float flt) { static_assert(sizeof(float) == sizeof(uint32_t), ""); static_assert(std::numeric_limits::is_iec559, ""); uint32_t bits = folly::bit_cast(flt); out_.writeBE(bits); return sizeof(bits); } inline uint32_t CompactProtocolWriter::writeString(folly::StringPiece str) { return writeBinary(str); } inline uint32_t CompactProtocolWriter::writeBinary(folly::StringPiece str) { return writeBinary(folly::ByteRange(str)); } inline uint32_t CompactProtocolWriter::writeBinary(folly::ByteRange str) { auto size = str.size(); checkBinarySize(size); uint32_t result = apache::thrift::util::writeVarint(out_, (int32_t)size); out_.push(str.data(), size); return static_cast(result + size); } inline uint32_t CompactProtocolWriter::writeBinary( const std::unique_ptr& str) { if (!str) { return writeI32(0); } return writeBinary(*str); } inline uint32_t CompactProtocolWriter::writeBinary(const folly::IOBuf& str) { return writeBinaryImpl(str); } inline uint32_t CompactProtocolWriter::writeRaw(const folly::IOBuf& str) { return writeBinaryImpl(str); } inline void CompactProtocolWriter::checkBinarySize(uint64_t size) { // We can't deserialize binary/string over 2GB, enforcing the same limit on // serializing for consistency constexpr uint64_t limit = std::numeric_limits::max(); if (size > limit) { TProtocolException::throwExceededSizeLimit(size, limit); } } template uint32_t CompactProtocolWriter::writeBinaryImpl(const folly::IOBuf& str) { size_t size = str.computeChainDataLength(); checkBinarySize(size); 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(size); } inline void CompactProtocolWriter::rewriteDouble(double dub, int64_t offset) { auto cursor = out_.tail(offset); cursor.writeBE(folly::bit_cast(dub)); } inline folly::io::Cursor CompactProtocolWriter::tail(size_t n) { auto cursor = out_.tail(n); return {cursor, n}; } /** * Functions that return the serialized size */ inline uint32_t CompactProtocolWriter::serializedMessageSize( folly::StringPiece name) const { // I32{version} + String{name} + I32{seqid} return 2 * serializedSizeI32() + serializedSizeString(name); } inline uint32_t CompactProtocolWriter::serializedFieldSize( const char* /*name*/, TType /*fieldType*/, int16_t /*fieldId*/) const { // byte + I16 return serializedSizeByte() + serializedSizeI16(); } inline uint32_t CompactProtocolWriter::serializedStructSize( const char* /*name*/) const { return 0; } inline uint32_t CompactProtocolWriter::serializedSizeMapBegin( TType /*keyType*/, TType /*valType*/, uint32_t /*size*/) const { return serializedSizeByte() + serializedSizeByte() + serializedSizeI32(); } inline uint32_t CompactProtocolWriter::serializedSizeMapEnd() const { return 0; } inline uint32_t CompactProtocolWriter::serializedSizeListBegin( TType /*elemType*/, uint32_t /*size*/) const { return serializedSizeByte() + serializedSizeI32(); } inline uint32_t CompactProtocolWriter::serializedSizeListEnd() const { return 0; } inline uint32_t CompactProtocolWriter::serializedSizeSetBegin( TType /*elemType*/, uint32_t /*size*/) const { return serializedSizeByte() + serializedSizeI32(); } inline uint32_t CompactProtocolWriter::serializedSizeSetEnd() const { return 0; } inline uint32_t CompactProtocolWriter::serializedSizeStop() const { return 1; } inline uint32_t CompactProtocolWriter::serializedSizeBool( bool /* val */) const { return 1; } inline uint32_t CompactProtocolWriter::serializedSizeByte( int8_t /* val */) const { return 1; } // Varint writes can be up to one additional byte inline uint32_t CompactProtocolWriter::serializedSizeI16( int16_t /*val*/) const { return 3; } inline uint32_t CompactProtocolWriter::serializedSizeI32( int32_t /*val*/) const { return 5; } inline uint32_t CompactProtocolWriter::serializedSizeI64( int64_t /*val*/) const { return 10; } inline uint32_t CompactProtocolWriter::serializedSizeDouble( double /*val*/) const { return 8; } inline uint32_t CompactProtocolWriter::serializedSizeFloat( float /*val*/) const { return 4; } inline uint32_t CompactProtocolWriter::serializedSizeString( folly::StringPiece str) const { return serializedSizeBinary(str); } inline uint32_t CompactProtocolWriter::serializedSizeBinary( folly::StringPiece str) const { return serializedSizeBinary(folly::ByteRange(str)); } inline uint32_t CompactProtocolWriter::serializedSizeBinary( folly::ByteRange v) const { // I32{length of string} + binary{string contents} return serializedSizeI32() + static_cast(v.size()); } inline uint32_t CompactProtocolWriter::serializedSizeBinary( const std::unique_ptr& v) const { return v ? serializedSizeBinary(*v) : 0; } inline uint32_t CompactProtocolWriter::serializedSizeBinary( const folly::IOBuf& v) const { size_t size = v.computeChainDataLength(); uint32_t limit = std::numeric_limits::max() - serializedSizeI32(); if (size > limit) { TProtocolException::throwExceededSizeLimit(size, limit); } return serializedSizeI32() + static_cast(size); } inline uint32_t CompactProtocolWriter::serializedSizeZCBinary( folly::StringPiece str) const { return serializedSizeZCBinary(folly::ByteRange(str)); } inline uint32_t CompactProtocolWriter::serializedSizeZCBinary( folly::ByteRange v) const { return serializedSizeBinary(v); } inline uint32_t CompactProtocolWriter::serializedSizeZCBinary( const std::unique_ptr& v) const { return v ? serializedSizeZCBinary(*v) : 0; } inline uint32_t CompactProtocolWriter::serializedSizeZCBinary( const IOBuf& v) const { size_t size = v.computeChainDataLength(); return (size > folly::IOBufQueue::kMaxPackCopy) ? serializedSizeI32() // too big to pack: size only : static_cast(size) + serializedSizeI32(); // size + packed data } /** * Reading functions */ inline 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); } inline void CompactProtocolReader::readMessageEnd() {} inline void CompactProtocolReader::readStructBegin(std::string& name) { descend(); if (!name.empty()) { name.clear(); } lastField_.push(lastFieldId_); lastFieldId_ = 0; } inline void CompactProtocolReader::readStructEnd() { lastFieldId_ = lastField_.top(); lastField_.pop(); ascend(); } inline 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; } inline void CompactProtocolReader::readFieldEnd() {} inline void CompactProtocolReader::readMapBegin( TType& keyType, TType& valType, uint32_t& size) { descend(); 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; } inline void CompactProtocolReader::readMapEnd() { ascend(); } inline void CompactProtocolReader::readListBegin( TType& elemType, uint32_t& size) { descend(); 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; } inline void CompactProtocolReader::readListEnd() { ascend(); } inline void CompactProtocolReader::readSetBegin( TType& elemType, uint32_t& size) { readListBegin(elemType, size); } inline void CompactProtocolReader::readSetEnd() { ascend(); } inline 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); } } inline void CompactProtocolReader::readBool( std::vector::reference value) { bool ret = false; readBool(ret); value = ret; } inline void CompactProtocolReader::readByte(int8_t& byte) { byte = in_.read(); } inline void CompactProtocolReader::readI16(int16_t& i16) { apache::thrift::util::readZigzaggedVarint(in_, i16); } inline void CompactProtocolReader::readI32(int32_t& i32) { apache::thrift::util::readZigzaggedVarint(in_, i32); } inline void CompactProtocolReader::readI64(int64_t& i64) { apache::thrift::util::readZigzaggedVarint(in_, i64); } inline void CompactProtocolReader::readDouble(double& dub) { static_assert(sizeof(double) == sizeof(uint64_t), ""); static_assert(std::numeric_limits::is_iec559, ""); uint64_t bits = in_.readBE(); dub = folly::bit_cast(bits); } inline void CompactProtocolReader::readFloat(float& flt) { static_assert(sizeof(float) == sizeof(uint32_t), ""); static_assert(std::numeric_limits::is_iec559, ""); uint32_t bits = in_.readBE(); flt = folly::bit_cast(bits); } inline 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 inline void CompactProtocolReader::readStringBody(StrType& str, int32_t size) { if (static_cast(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 inline void CompactProtocolReader::readString(StrType& str) { int32_t size = 0; readStringSize(size); readStringBody(str, size); } template inline void CompactProtocolReader::readBinary(StrType& str) { readString(str); } inline void CompactProtocolReader::readBinary( std::unique_ptr& str) { if (!str) { str = std::make_unique(); } readBinary(*str); } inline 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(); } } inline TType CompactProtocolReader::getType(int8_t type) { using apache::thrift::detail::compact::CTypeToTType; if (LIKELY( static_cast(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(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(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; } inline void CompactProtocolReader::readStructBeginWithState( StructReadState& /* state */) {} inline 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_