Back to home page

EIC code displayed by LXR

 
 

    


Warning, /include/thrift/protocol/TCompactProtocol.tcc is written in an unsupported language. File is not indexed.

0001 /*
0002  * Licensed to the Apache Software Foundation (ASF) under one
0003  * or more contributor license agreements. See the NOTICE file
0004  * distributed with this work for additional information
0005  * regarding copyright ownership. The ASF licenses this file
0006  * to you under the Apache License, Version 2.0 (the
0007  * "License"); you may not use this file except in compliance
0008  * with the License. You may obtain a copy of the License at
0009  *
0010  *   http://www.apache.org/licenses/LICENSE-2.0
0011  *
0012  * Unless required by applicable law or agreed to in writing,
0013  * software distributed under the License is distributed on an
0014  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
0015  * KIND, either express or implied. See the License for the
0016  * specific language governing permissions and limitations
0017  * under the License.
0018  */
0019 #ifndef _THRIFT_PROTOCOL_TCOMPACTPROTOCOL_TCC_
0020 #define _THRIFT_PROTOCOL_TCOMPACTPROTOCOL_TCC_ 1
0021 
0022 #include <limits>
0023 #include <cstdlib>
0024 
0025 #include "thrift/config.h"
0026 
0027 /*
0028  * TCompactProtocol::i*ToZigzag depend on the fact that the right shift
0029  * operator on a signed integer is an arithmetic (sign-extending) shift.
0030  * If this is not the case, the current implementation will not work.
0031  * If anyone encounters this error, we can try to figure out the best
0032  * way to implement an arithmetic right shift on their platform.
0033  */
0034 #if !defined(SIGNED_RIGHT_SHIFT_IS) || !defined(ARITHMETIC_RIGHT_SHIFT)
0035 # error "Unable to determine the behavior of a signed right shift"
0036 #endif
0037 #if SIGNED_RIGHT_SHIFT_IS != ARITHMETIC_RIGHT_SHIFT
0038 # error "TCompactProtocol currently only works if a signed right shift is arithmetic"
0039 #endif
0040 
0041 #ifdef __GNUC__
0042 #define UNLIKELY(val) (__builtin_expect((val), 0))
0043 #else
0044 #define UNLIKELY(val) (val)
0045 #endif
0046 
0047 namespace apache { namespace thrift { namespace protocol {
0048 
0049 namespace detail { namespace compact {
0050 
0051 enum Types {
0052   CT_STOP           = 0x00,
0053   CT_BOOLEAN_TRUE   = 0x01,
0054   CT_BOOLEAN_FALSE  = 0x02,
0055   CT_BYTE           = 0x03,
0056   CT_I16            = 0x04,
0057   CT_I32            = 0x05,
0058   CT_I64            = 0x06,
0059   CT_DOUBLE         = 0x07,
0060   CT_BINARY         = 0x08,
0061   CT_LIST           = 0x09,
0062   CT_SET            = 0x0A,
0063   CT_MAP            = 0x0B,
0064   CT_STRUCT         = 0x0C
0065 };
0066 
0067 const int8_t TTypeToCType[16] = {
0068   CT_STOP, // T_STOP
0069   0, // unused
0070   CT_BOOLEAN_TRUE, // T_BOOL
0071   CT_BYTE, // T_BYTE
0072   CT_DOUBLE, // T_DOUBLE
0073   0, // unused
0074   CT_I16, // T_I16
0075   0, // unused
0076   CT_I32, // T_I32
0077   0, // unused
0078   CT_I64, // T_I64
0079   CT_BINARY, // T_STRING
0080   CT_STRUCT, // T_STRUCT
0081   CT_MAP, // T_MAP
0082   CT_SET, // T_SET
0083   CT_LIST, // T_LIST
0084 };
0085 
0086 }} // end detail::compact namespace
0087 
0088 
0089 template <class Transport_>
0090 uint32_t TCompactProtocolT<Transport_>::writeMessageBegin(
0091     const std::string& name,
0092     const TMessageType messageType,
0093     const int32_t seqid) {
0094   uint32_t wsize = 0;
0095   wsize += writeByte(PROTOCOL_ID);
0096   wsize += writeByte((VERSION_N & VERSION_MASK) | (((int32_t)messageType << TYPE_SHIFT_AMOUNT) & TYPE_MASK));
0097   wsize += writeVarint32(seqid);
0098   wsize += writeString(name);
0099   return wsize;
0100 }
0101 
0102 /**
0103  * Write a field header containing the field id and field type. If the
0104  * difference between the current field id and the last one is small (< 15),
0105  * then the field id will be encoded in the 4 MSB as a delta. Otherwise, the
0106  * field id will follow the type header as a zigzag varint.
0107  */
0108 template <class Transport_>
0109 uint32_t TCompactProtocolT<Transport_>::writeFieldBegin(const char* name,
0110                                                         const TType fieldType,
0111                                                         const int16_t fieldId) {
0112   if (fieldType == T_BOOL) {
0113     booleanField_.name = name;
0114     booleanField_.fieldType = fieldType;
0115     booleanField_.fieldId = fieldId;
0116   } else {
0117     return writeFieldBeginInternal(name, fieldType, fieldId, -1);
0118   }
0119   return 0;
0120 }
0121 
0122 /**
0123  * Write the STOP symbol so we know there are no more fields in this struct.
0124  */
0125 template <class Transport_>
0126 uint32_t TCompactProtocolT<Transport_>::writeFieldStop() {
0127   return writeByte(T_STOP);
0128 }
0129 
0130 /**
0131  * Write a struct begin. This doesn't actually put anything on the wire. We
0132  * use it as an opportunity to put special placeholder markers on the field
0133  * stack so we can get the field id deltas correct.
0134  */
0135 template <class Transport_>
0136 uint32_t TCompactProtocolT<Transport_>::writeStructBegin(const char* name) {
0137   (void) name;
0138   lastField_.push(lastFieldId_);
0139   lastFieldId_ = 0;
0140   return 0;
0141 }
0142 
0143 /**
0144  * Write a struct end. This doesn't actually put anything on the wire. We use
0145  * this as an opportunity to pop the last field from the current struct off
0146  * of the field stack.
0147  */
0148 template <class Transport_>
0149 uint32_t TCompactProtocolT<Transport_>::writeStructEnd() {
0150   lastFieldId_ = lastField_.top();
0151   lastField_.pop();
0152   return 0;
0153 }
0154 
0155 /**
0156  * Write a List header.
0157  */
0158 template <class Transport_>
0159 uint32_t TCompactProtocolT<Transport_>::writeListBegin(const TType elemType,
0160                                                        const uint32_t size) {
0161   return writeCollectionBegin(elemType, size);
0162 }
0163 
0164 /**
0165  * Write a set header.
0166  */
0167 template <class Transport_>
0168 uint32_t TCompactProtocolT<Transport_>::writeSetBegin(const TType elemType,
0169                                                       const uint32_t size) {
0170   return writeCollectionBegin(elemType, size);
0171 }
0172 
0173 /**
0174  * Write a map header. If the map is empty, omit the key and value type
0175  * headers, as we don't need any additional information to skip it.
0176  */
0177 template <class Transport_>
0178 uint32_t TCompactProtocolT<Transport_>::writeMapBegin(const TType keyType,
0179                                                       const TType valType,
0180                                                       const uint32_t size) {
0181   uint32_t wsize = 0;
0182 
0183   if (size == 0) {
0184     wsize += writeByte(0);
0185   } else {
0186     wsize += writeVarint32(size);
0187     wsize += writeByte(getCompactType(keyType) << 4 | getCompactType(valType));
0188   }
0189   return wsize;
0190 }
0191 
0192 /**
0193  * Write a boolean value. Potentially, this could be a boolean field, in
0194  * which case the field header info isn't written yet. If so, decide what the
0195  * right type header is for the value and then write the field header.
0196  * Otherwise, write a single byte.
0197  */
0198 template <class Transport_>
0199 uint32_t TCompactProtocolT<Transport_>::writeBool(const bool value) {
0200   uint32_t wsize = 0;
0201 
0202   if (booleanField_.name != nullptr) {
0203     // we haven't written the field header yet
0204     wsize
0205       += writeFieldBeginInternal(booleanField_.name,
0206                                  booleanField_.fieldType,
0207                                  booleanField_.fieldId,
0208                                  static_cast<int8_t>(value
0209                                                      ? detail::compact::CT_BOOLEAN_TRUE
0210                                                      : detail::compact::CT_BOOLEAN_FALSE));
0211     booleanField_.name = nullptr;
0212   } else {
0213     // we're not part of a field, so just write the value
0214     wsize
0215       += writeByte(static_cast<int8_t>(value
0216                                        ? detail::compact::CT_BOOLEAN_TRUE
0217                                        : detail::compact::CT_BOOLEAN_FALSE));
0218   }
0219   return wsize;
0220 }
0221 
0222 template <class Transport_>
0223 uint32_t TCompactProtocolT<Transport_>::writeByte(const int8_t byte) {
0224   trans_->write((uint8_t*)&byte, 1);
0225   return 1;
0226 }
0227 
0228 /**
0229  * Write an i16 as a zigzag varint.
0230  */
0231 template <class Transport_>
0232 uint32_t TCompactProtocolT<Transport_>::writeI16(const int16_t i16) {
0233   return writeVarint32(i32ToZigzag(i16));
0234 }
0235 
0236 /**
0237  * Write an i32 as a zigzag varint.
0238  */
0239 template <class Transport_>
0240 uint32_t TCompactProtocolT<Transport_>::writeI32(const int32_t i32) {
0241   return writeVarint32(i32ToZigzag(i32));
0242 }
0243 
0244 /**
0245  * Write an i64 as a zigzag varint.
0246  */
0247 template <class Transport_>
0248 uint32_t TCompactProtocolT<Transport_>::writeI64(const int64_t i64) {
0249   return writeVarint64(i64ToZigzag(i64));
0250 }
0251 
0252 /**
0253  * Write a double to the wire as 8 bytes.
0254  */
0255 template <class Transport_>
0256 uint32_t TCompactProtocolT<Transport_>::writeDouble(const double dub) {
0257   static_assert(sizeof(double) == sizeof(uint64_t), "sizeof(double) == sizeof(uint64_t)");
0258   static_assert(std::numeric_limits<double>::is_iec559, "std::numeric_limits<double>::is_iec559");
0259 
0260   auto bits = bitwise_cast<uint64_t>(dub);
0261   bits = THRIFT_htolell(bits);
0262   trans_->write((uint8_t*)&bits, 8);
0263   return 8;
0264 }
0265 
0266 /**
0267  * Write a string to the wire with a varint size preceding.
0268  */
0269 template <class Transport_>
0270 uint32_t TCompactProtocolT<Transport_>::writeString(const std::string& str) {
0271   return writeBinary(str);
0272 }
0273 
0274 template <class Transport_>
0275 uint32_t TCompactProtocolT<Transport_>::writeBinary(const std::string& str) {
0276   if(str.size() > (std::numeric_limits<uint32_t>::max)())
0277     throw TProtocolException(TProtocolException::SIZE_LIMIT);
0278   auto ssize = static_cast<uint32_t>(str.size());
0279   uint32_t wsize = writeVarint32(ssize) ;
0280   // checking ssize + wsize > uint_max, but we don't want to overflow while checking for overflows.
0281   // transforming the check to ssize > uint_max - wsize
0282   if(ssize > (std::numeric_limits<uint32_t>::max)() - wsize)
0283     throw TProtocolException(TProtocolException::SIZE_LIMIT);
0284   wsize += ssize;
0285   trans_->write((uint8_t*)str.data(), ssize);
0286   return wsize;
0287 }
0288 
0289 //
0290 // Internal Writing methods
0291 //
0292 
0293 /**
0294  * The workhorse of writeFieldBegin. It has the option of doing a
0295  * 'type override' of the type header. This is used specifically in the
0296  * boolean field case.
0297  */
0298 template <class Transport_>
0299 int32_t TCompactProtocolT<Transport_>::writeFieldBeginInternal(
0300     const char* name,
0301     const TType fieldType,
0302     const int16_t fieldId,
0303     int8_t typeOverride) {
0304   (void) name;
0305   uint32_t wsize = 0;
0306 
0307   // if there's a type override, use that.
0308   int8_t typeToWrite = (typeOverride == -1 ? getCompactType(fieldType) : typeOverride);
0309 
0310   // check if we can use delta encoding for the field id
0311   if (fieldId > lastFieldId_ && fieldId - lastFieldId_ <= 15) {
0312     // write them together
0313     wsize += writeByte(static_cast<int8_t>((fieldId - lastFieldId_)
0314                                            << 4 | typeToWrite));
0315   } else {
0316     // write them separate
0317     wsize += writeByte(typeToWrite);
0318     wsize += writeI16(fieldId);
0319   }
0320 
0321   lastFieldId_ = fieldId;
0322   return wsize;
0323 }
0324 
0325 /**
0326  * Abstract method for writing the start of lists and sets. List and sets on
0327  * the wire differ only by the type indicator.
0328  */
0329 template <class Transport_>
0330 uint32_t TCompactProtocolT<Transport_>::writeCollectionBegin(const TType elemType,
0331                                                              int32_t size) {
0332   uint32_t wsize = 0;
0333   if (size <= 14) {
0334     wsize += writeByte(static_cast<int8_t>(size
0335                                            << 4 | getCompactType(elemType)));
0336   } else {
0337     wsize += writeByte(0xf0 | getCompactType(elemType));
0338     wsize += writeVarint32(size);
0339   }
0340   return wsize;
0341 }
0342 
0343 /**
0344  * Write an i32 as a varint. Results in 1-5 bytes on the wire.
0345  */
0346 template <class Transport_>
0347 uint32_t TCompactProtocolT<Transport_>::writeVarint32(uint32_t n) {
0348   uint8_t buf[5];
0349   uint32_t wsize = 0;
0350 
0351   while (true) {
0352     if ((n & ~0x7F) == 0) {
0353       buf[wsize++] = (int8_t)n;
0354       break;
0355     } else {
0356       buf[wsize++] = (int8_t)((n & 0x7F) | 0x80);
0357       n >>= 7;
0358     }
0359   }
0360   trans_->write(buf, wsize);
0361   return wsize;
0362 }
0363 
0364 /**
0365  * Write an i64 as a varint. Results in 1-10 bytes on the wire.
0366  */
0367 template <class Transport_>
0368 uint32_t TCompactProtocolT<Transport_>::writeVarint64(uint64_t n) {
0369   uint8_t buf[10];
0370   uint32_t wsize = 0;
0371 
0372   while (true) {
0373     if ((n & ~0x7FL) == 0) {
0374       buf[wsize++] = (int8_t)n;
0375       break;
0376     } else {
0377       buf[wsize++] = (int8_t)((n & 0x7F) | 0x80);
0378       n >>= 7;
0379     }
0380   }
0381   trans_->write(buf, wsize);
0382   return wsize;
0383 }
0384 
0385 /**
0386  * Convert l into a zigzag long. This allows negative numbers to be
0387  * represented compactly as a varint.
0388  */
0389 template <class Transport_>
0390 uint64_t TCompactProtocolT<Transport_>::i64ToZigzag(const int64_t l) {
0391   return (static_cast<uint64_t>(l) << 1) ^ (l >> 63);
0392 }
0393 
0394 /**
0395  * Convert n into a zigzag int. This allows negative numbers to be
0396  * represented compactly as a varint.
0397  */
0398 template <class Transport_>
0399 uint32_t TCompactProtocolT<Transport_>::i32ToZigzag(const int32_t n) {
0400   return (static_cast<uint32_t>(n) << 1) ^ (n >> 31);
0401 }
0402 
0403 /**
0404  * Given a TType value, find the appropriate detail::compact::Types value
0405  */
0406 template <class Transport_>
0407 int8_t TCompactProtocolT<Transport_>::getCompactType(const TType ttype) {
0408   return detail::compact::TTypeToCType[ttype];
0409 }
0410 
0411 //
0412 // Reading Methods
0413 //
0414 
0415 /**
0416  * Read a message header.
0417  */
0418 template <class Transport_>
0419 uint32_t TCompactProtocolT<Transport_>::readMessageBegin(
0420     std::string& name,
0421     TMessageType& messageType,
0422     int32_t& seqid) {
0423   uint32_t rsize = 0;
0424   int8_t protocolId;
0425   int8_t versionAndType;
0426   int8_t version;
0427 
0428   rsize += readByte(protocolId);
0429   if (protocolId != PROTOCOL_ID) {
0430     throw TProtocolException(TProtocolException::BAD_VERSION, "Bad protocol identifier");
0431   }
0432 
0433   rsize += readByte(versionAndType);
0434   version = (int8_t)(versionAndType & VERSION_MASK);
0435   if (version != VERSION_N) {
0436     throw TProtocolException(TProtocolException::BAD_VERSION, "Bad protocol version");
0437   }
0438 
0439   messageType = (TMessageType)((versionAndType >> TYPE_SHIFT_AMOUNT) & TYPE_BITS);
0440   rsize += readVarint32(seqid);
0441   rsize += readString(name);
0442 
0443   return rsize;
0444 }
0445 
0446 /**
0447  * Read a struct begin. There's nothing on the wire for this, but it is our
0448  * opportunity to push a new struct begin marker on the field stack.
0449  */
0450 template <class Transport_>
0451 uint32_t TCompactProtocolT<Transport_>::readStructBegin(std::string& name) {
0452   name = "";
0453   lastField_.push(lastFieldId_);
0454   lastFieldId_ = 0;
0455   return 0;
0456 }
0457 
0458 /**
0459  * Doesn't actually consume any wire data, just removes the last field for
0460  * this struct from the field stack.
0461  */
0462 template <class Transport_>
0463 uint32_t TCompactProtocolT<Transport_>::readStructEnd() {
0464   lastFieldId_ = lastField_.top();
0465   lastField_.pop();
0466   return 0;
0467 }
0468 
0469 /**
0470  * Read a field header off the wire.
0471  */
0472 template <class Transport_>
0473 uint32_t TCompactProtocolT<Transport_>::readFieldBegin(std::string& name,
0474                                                        TType& fieldType,
0475                                                        int16_t& fieldId) {
0476   (void) name;
0477   uint32_t rsize = 0;
0478   int8_t byte;
0479   int8_t type;
0480 
0481   rsize += readByte(byte);
0482   type = (byte & 0x0f);
0483 
0484   // if it's a stop, then we can return immediately, as the struct is over.
0485   if (type == T_STOP) {
0486     fieldType = T_STOP;
0487     fieldId = 0;
0488     return rsize;
0489   }
0490 
0491   // mask off the 4 MSB of the type header. it could contain a field id delta.
0492   auto modifier = (int16_t)(((uint8_t)byte & 0xf0) >> 4);
0493   if (modifier == 0) {
0494     // not a delta, look ahead for the zigzag varint field id.
0495     rsize += readI16(fieldId);
0496   } else {
0497     fieldId = (int16_t)(lastFieldId_ + modifier);
0498   }
0499   fieldType = getTType(type);
0500 
0501   // if this happens to be a boolean field, the value is encoded in the type
0502   if (type == detail::compact::CT_BOOLEAN_TRUE ||
0503       type == detail::compact::CT_BOOLEAN_FALSE) {
0504     // save the boolean value in a special instance variable.
0505     boolValue_.hasBoolValue = true;
0506     boolValue_.boolValue =
0507       (type == detail::compact::CT_BOOLEAN_TRUE ? true : false);
0508   }
0509 
0510   // push the new field onto the field stack so we can keep the deltas going.
0511   lastFieldId_ = fieldId;
0512   return rsize;
0513 }
0514 
0515 /**
0516  * Read a map header off the wire. If the size is zero, skip reading the key
0517  * and value type. This means that 0-length maps will yield TMaps without the
0518  * "correct" types.
0519  */
0520 template <class Transport_>
0521 uint32_t TCompactProtocolT<Transport_>::readMapBegin(TType& keyType,
0522                                                      TType& valType,
0523                                                      uint32_t& size) {
0524   uint32_t rsize = 0;
0525   int8_t kvType = 0;
0526   int32_t msize = 0;
0527 
0528   rsize += readVarint32(msize);
0529   if (msize != 0)
0530     rsize += readByte(kvType);
0531 
0532   if (msize < 0) {
0533     throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
0534   } else if (container_limit_ && msize > container_limit_) {
0535     throw TProtocolException(TProtocolException::SIZE_LIMIT);
0536   }
0537 
0538   keyType = getTType((int8_t)((uint8_t)kvType >> 4));
0539   valType = getTType((int8_t)((uint8_t)kvType & 0xf));
0540   size = (uint32_t)msize;
0541 
0542   TMap map(keyType, valType, size);
0543   checkReadBytesAvailable(map);
0544 
0545   return rsize;
0546 }
0547 
0548 /**
0549  * Read a list header off the wire. If the list size is 0-14, the size will
0550  * be packed into the element type header. If it's a longer list, the 4 MSB
0551  * of the element type header will be 0xF, and a varint will follow with the
0552  * true size.
0553  */
0554 template <class Transport_>
0555 uint32_t TCompactProtocolT<Transport_>::readListBegin(TType& elemType,
0556                                                       uint32_t& size) {
0557   int8_t size_and_type;
0558   uint32_t rsize = 0;
0559   int32_t lsize;
0560 
0561   rsize += readByte(size_and_type);
0562 
0563   lsize = ((uint8_t)size_and_type >> 4) & 0x0f;
0564   if (lsize == 15) {
0565     rsize += readVarint32(lsize);
0566   }
0567 
0568   if (lsize < 0) {
0569     throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
0570   } else if (container_limit_ && lsize > container_limit_) {
0571     throw TProtocolException(TProtocolException::SIZE_LIMIT);
0572   }
0573 
0574   elemType = getTType((int8_t)(size_and_type & 0x0f));
0575   size = (uint32_t)lsize;
0576 
0577   TList list(elemType, size);
0578   checkReadBytesAvailable(list);
0579 
0580   return rsize;
0581 }
0582 
0583 /**
0584  * Read a set header off the wire. If the set size is 0-14, the size will
0585  * be packed into the element type header. If it's a longer set, the 4 MSB
0586  * of the element type header will be 0xF, and a varint will follow with the
0587  * true size.
0588  */
0589 template <class Transport_>
0590 uint32_t TCompactProtocolT<Transport_>::readSetBegin(TType& elemType,
0591                                                      uint32_t& size) {
0592   return readListBegin(elemType, size);
0593 }
0594 
0595 /**
0596  * Read a boolean off the wire. If this is a boolean field, the value should
0597  * already have been read during readFieldBegin, so we'll just consume the
0598  * pre-stored value. Otherwise, read a byte.
0599  */
0600 template <class Transport_>
0601 uint32_t TCompactProtocolT<Transport_>::readBool(bool& value) {
0602   if (boolValue_.hasBoolValue == true) {
0603     value = boolValue_.boolValue;
0604     boolValue_.hasBoolValue = false;
0605     return 0;
0606   } else {
0607     int8_t val;
0608     readByte(val);
0609     value = (val == detail::compact::CT_BOOLEAN_TRUE);
0610     return 1;
0611   }
0612 }
0613 
0614 /**
0615  * Read a single byte off the wire. Nothing interesting here.
0616  */
0617 template <class Transport_>
0618 uint32_t TCompactProtocolT<Transport_>::readByte(int8_t& byte) {
0619   uint8_t b[1];
0620   trans_->readAll(b, 1);
0621   byte = *(int8_t*)b;
0622   return 1;
0623 }
0624 
0625 /**
0626  * Read an i16 from the wire as a zigzag varint.
0627  */
0628 template <class Transport_>
0629 uint32_t TCompactProtocolT<Transport_>::readI16(int16_t& i16) {
0630   int32_t value;
0631   uint32_t rsize = readVarint32(value);
0632   i16 = (int16_t)zigzagToI32(value);
0633   return rsize;
0634 }
0635 
0636 /**
0637  * Read an i32 from the wire as a zigzag varint.
0638  */
0639 template <class Transport_>
0640 uint32_t TCompactProtocolT<Transport_>::readI32(int32_t& i32) {
0641   int32_t value;
0642   uint32_t rsize = readVarint32(value);
0643   i32 = zigzagToI32(value);
0644   return rsize;
0645 }
0646 
0647 /**
0648  * Read an i64 from the wire as a zigzag varint.
0649  */
0650 template <class Transport_>
0651 uint32_t TCompactProtocolT<Transport_>::readI64(int64_t& i64) {
0652   int64_t value;
0653   uint32_t rsize = readVarint64(value);
0654   i64 = zigzagToI64(value);
0655   return rsize;
0656 }
0657 
0658 /**
0659  * No magic here - just read a double off the wire.
0660  */
0661 template <class Transport_>
0662 uint32_t TCompactProtocolT<Transport_>::readDouble(double& dub) {
0663   static_assert(sizeof(double) == sizeof(uint64_t), "sizeof(double) == sizeof(uint64_t)");
0664   static_assert(std::numeric_limits<double>::is_iec559, "std::numeric_limits<double>::is_iec559");
0665 
0666   union {
0667     uint64_t bits;
0668     uint8_t b[8];
0669   } u;
0670   trans_->readAll(u.b, 8);
0671   u.bits = THRIFT_letohll(u.bits);
0672   dub = bitwise_cast<double>(u.bits);
0673   return 8;
0674 }
0675 
0676 template <class Transport_>
0677 uint32_t TCompactProtocolT<Transport_>::readString(std::string& str) {
0678   return readBinary(str);
0679 }
0680 
0681 /**
0682  * Read a byte[] from the wire.
0683  */
0684 template <class Transport_>
0685 uint32_t TCompactProtocolT<Transport_>::readBinary(std::string& str) {
0686   int32_t rsize = 0;
0687   int32_t size;
0688 
0689   rsize += readVarint32(size);
0690   // Catch empty string case
0691   if (size == 0) {
0692     str = "";
0693     return rsize;
0694   }
0695 
0696   // Catch error cases
0697   if (size < 0) {
0698     throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
0699   }
0700   if (string_limit_ > 0 && size > string_limit_) {
0701     throw TProtocolException(TProtocolException::SIZE_LIMIT);
0702   }
0703 
0704   // Use the heap here to prevent stack overflow for v. large strings
0705   if (size > string_buf_size_ || string_buf_ == nullptr) {
0706     void* new_string_buf = std::realloc(string_buf_, (uint32_t)size);
0707     if (new_string_buf == nullptr) {
0708       throw std::bad_alloc();
0709     }
0710     string_buf_ = (uint8_t*)new_string_buf;
0711     string_buf_size_ = size;
0712   }
0713   trans_->readAll(string_buf_, size);
0714   str.assign((char*)string_buf_, size);
0715 
0716   trans_->checkReadBytesAvailable(rsize + (uint32_t)size);
0717 
0718   return rsize + (uint32_t)size;
0719 }
0720 
0721 /**
0722  * Read an i32 from the wire as a varint. The MSB of each byte is set
0723  * if there is another byte to follow. This can read up to 5 bytes.
0724  */
0725 template <class Transport_>
0726 uint32_t TCompactProtocolT<Transport_>::readVarint32(int32_t& i32) {
0727   int64_t val;
0728   uint32_t rsize = readVarint64(val);
0729   i32 = (int32_t)val;
0730   return rsize;
0731 }
0732 
0733 /**
0734  * Read an i64 from the wire as a proper varint. The MSB of each byte is set
0735  * if there is another byte to follow. This can read up to 10 bytes.
0736  */
0737 template <class Transport_>
0738 uint32_t TCompactProtocolT<Transport_>::readVarint64(int64_t& i64) {
0739   uint32_t rsize = 0;
0740   uint64_t val = 0;
0741   int shift = 0;
0742   uint8_t buf[10];  // 64 bits / (7 bits/byte) = 10 bytes.
0743   uint32_t buf_size = sizeof(buf);
0744   const uint8_t* borrowed = trans_->borrow(buf, &buf_size);
0745 
0746   // Fast path.
0747   if (borrowed != nullptr) {
0748     while (true) {
0749       uint8_t byte = borrowed[rsize];
0750       rsize++;
0751       val |= (uint64_t)(byte & 0x7f) << shift;
0752       shift += 7;
0753       if (!(byte & 0x80)) {
0754         i64 = val;
0755         trans_->consume(rsize);
0756         return rsize;
0757       }
0758       // Have to check for invalid data so we don't crash.
0759       if (UNLIKELY(rsize == sizeof(buf))) {
0760         throw TProtocolException(TProtocolException::INVALID_DATA, "Variable-length int over 10 bytes.");
0761       }
0762     }
0763   }
0764 
0765   // Slow path.
0766   else {
0767     while (true) {
0768       uint8_t byte;
0769       rsize += trans_->readAll(&byte, 1);
0770       val |= (uint64_t)(byte & 0x7f) << shift;
0771       shift += 7;
0772       if (!(byte & 0x80)) {
0773         i64 = val;
0774         return rsize;
0775       }
0776       // Might as well check for invalid data on the slow path too.
0777       if (UNLIKELY(rsize >= sizeof(buf))) {
0778         throw TProtocolException(TProtocolException::INVALID_DATA, "Variable-length int over 10 bytes.");
0779       }
0780     }
0781   }
0782 }
0783 
0784 /**
0785  * Convert from zigzag int to int.
0786  */
0787 template <class Transport_>
0788 int32_t TCompactProtocolT<Transport_>::zigzagToI32(uint32_t n) {
0789   return (n >> 1) ^ static_cast<uint32_t>(-static_cast<int32_t>(n & 1));
0790 }
0791 
0792 /**
0793  * Convert from zigzag long to long.
0794  */
0795 template <class Transport_>
0796 int64_t TCompactProtocolT<Transport_>::zigzagToI64(uint64_t n) {
0797   return (n >> 1) ^ static_cast<uint64_t>(-static_cast<int64_t>(n & 1));
0798 }
0799 
0800 template <class Transport_>
0801 TType TCompactProtocolT<Transport_>::getTType(int8_t type) {
0802   switch (type) {
0803     case T_STOP:
0804       return T_STOP;
0805     case detail::compact::CT_BOOLEAN_FALSE:
0806     case detail::compact::CT_BOOLEAN_TRUE:
0807       return T_BOOL;
0808     case detail::compact::CT_BYTE:
0809       return T_BYTE;
0810     case detail::compact::CT_I16:
0811       return T_I16;
0812     case detail::compact::CT_I32:
0813       return T_I32;
0814     case detail::compact::CT_I64:
0815       return T_I64;
0816     case detail::compact::CT_DOUBLE:
0817       return T_DOUBLE;
0818     case detail::compact::CT_BINARY:
0819       return T_STRING;
0820     case detail::compact::CT_LIST:
0821       return T_LIST;
0822     case detail::compact::CT_SET:
0823       return T_SET;
0824     case detail::compact::CT_MAP:
0825       return T_MAP;
0826     case detail::compact::CT_STRUCT:
0827       return T_STRUCT;
0828     default:
0829       throw TException(std::string("don't know what type: ") + (char)type);
0830   }
0831 }
0832 
0833 // Return the minimum number of bytes a type will consume on the wire
0834 template <class Transport_>
0835 int TCompactProtocolT<Transport_>::getMinSerializedSize(TType type)
0836 {
0837   switch (type)
0838   {
0839     case T_STOP:    return 0;
0840     case T_VOID:    return 0;
0841     case T_BOOL:   return sizeof(int8_t);
0842     case T_DOUBLE: return 8;  // uses fixedLongToBytes() which always writes 8 bytes
0843     case T_BYTE: return sizeof(int8_t);
0844     case T_I16:     return sizeof(int8_t);  // zigzag
0845     case T_I32:     return sizeof(int8_t);  // zigzag
0846     case T_I64:     return sizeof(int8_t);  // zigzag
0847     case T_STRING: return sizeof(int8_t);  // string length
0848     case T_STRUCT:  return 0;             // empty struct
0849     case T_MAP:     return sizeof(int8_t);  // element count
0850     case T_SET:    return sizeof(int8_t);  // element count
0851     case T_LIST:    return sizeof(int8_t);  // element count
0852     default: throw TProtocolException(TProtocolException::UNKNOWN, "unrecognized type code");
0853   }
0854 }
0855 
0856 
0857 }}} // apache::thrift::protocol
0858 
0859 #endif // _THRIFT_PROTOCOL_TCOMPACTPROTOCOL_TCC_