THRIFT-922. cpp: Templatize binary and compact protocol

Convert TBinaryProtocol and TCompactProtocol to template classes, taking
the transport class as a template parameter.  This allows them to make
non-virtual calls when using the template, improving serialization
performance.

git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@1005136 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/cpp/src/protocol/TBinaryProtocol.tcc b/lib/cpp/src/protocol/TBinaryProtocol.tcc
new file mode 100644
index 0000000..1433a4f
--- /dev/null
+++ b/lib/cpp/src/protocol/TBinaryProtocol.tcc
@@ -0,0 +1,451 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 _THRIFT_PROTOCOL_TBINARYPROTOCOL_TCC_
+#define _THRIFT_PROTOCOL_TBINARYPROTOCOL_TCC_ 1
+
+#include "TBinaryProtocol.h"
+
+#include <limits>
+
+
+namespace apache { namespace thrift { namespace protocol {
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::writeMessageBegin(const std::string& name,
+                                                         const TMessageType messageType,
+                                                         const int32_t seqid) {
+  if (this->strict_write_) {
+    int32_t version = (VERSION_1) | ((int32_t)messageType);
+    uint32_t wsize = 0;
+    wsize += writeI32(version);
+    wsize += writeString(name);
+    wsize += writeI32(seqid);
+    return wsize;
+  } else {
+    uint32_t wsize = 0;
+    wsize += writeString(name);
+    wsize += writeByte((int8_t)messageType);
+    wsize += writeI32(seqid);
+    return wsize;
+  }
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::writeMessageEnd() {
+  return 0;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::writeStructBegin(const char* name) {
+  return 0;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::writeStructEnd() {
+  return 0;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::writeFieldBegin(const char* name,
+                                                       const TType fieldType,
+                                                       const int16_t fieldId) {
+  uint32_t wsize = 0;
+  wsize += writeByte((int8_t)fieldType);
+  wsize += writeI16(fieldId);
+  return wsize;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::writeFieldEnd() {
+  return 0;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::writeFieldStop() {
+  return
+    writeByte((int8_t)T_STOP);
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::writeMapBegin(const TType keyType,
+                                                     const TType valType,
+                                                     const uint32_t size) {
+  uint32_t wsize = 0;
+  wsize += writeByte((int8_t)keyType);
+  wsize += writeByte((int8_t)valType);
+  wsize += writeI32((int32_t)size);
+  return wsize;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::writeMapEnd() {
+  return 0;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::writeListBegin(const TType elemType,
+                                                      const uint32_t size) {
+  uint32_t wsize = 0;
+  wsize += writeByte((int8_t) elemType);
+  wsize += writeI32((int32_t)size);
+  return wsize;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::writeListEnd() {
+  return 0;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::writeSetBegin(const TType elemType,
+                                                     const uint32_t size) {
+  uint32_t wsize = 0;
+  wsize += writeByte((int8_t)elemType);
+  wsize += writeI32((int32_t)size);
+  return wsize;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::writeSetEnd() {
+  return 0;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::writeBool(const bool value) {
+  uint8_t tmp =  value ? 1 : 0;
+  this->trans_->write(&tmp, 1);
+  return 1;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::writeByte(const int8_t byte) {
+  this->trans_->write((uint8_t*)&byte, 1);
+  return 1;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::writeI16(const int16_t i16) {
+  int16_t net = (int16_t)htons(i16);
+  this->trans_->write((uint8_t*)&net, 2);
+  return 2;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::writeI32(const int32_t i32) {
+  int32_t net = (int32_t)htonl(i32);
+  this->trans_->write((uint8_t*)&net, 4);
+  return 4;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::writeI64(const int64_t i64) {
+  int64_t net = (int64_t)htonll(i64);
+  this->trans_->write((uint8_t*)&net, 8);
+  return 8;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::writeDouble(const double dub) {
+  BOOST_STATIC_ASSERT(sizeof(double) == sizeof(uint64_t));
+  BOOST_STATIC_ASSERT(std::numeric_limits<double>::is_iec559);
+
+  uint64_t bits = bitwise_cast<uint64_t>(dub);
+  bits = htonll(bits);
+  this->trans_->write((uint8_t*)&bits, 8);
+  return 8;
+}
+
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::writeString(const std::string& str) {
+  uint32_t size = str.size();
+  uint32_t result = writeI32((int32_t)size);
+  if (size > 0) {
+    this->trans_->write((uint8_t*)str.data(), size);
+  }
+  return result + size;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::writeBinary(const std::string& str) {
+  return TBinaryProtocolT<Transport_>::writeString(str);
+}
+
+/**
+ * Reading functions
+ */
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::readMessageBegin(std::string& name,
+                                                        TMessageType& messageType,
+                                                        int32_t& seqid) {
+  uint32_t result = 0;
+  int32_t sz;
+  result += readI32(sz);
+
+  if (sz < 0) {
+    // Check for correct version number
+    int32_t version = sz & VERSION_MASK;
+    if (version != VERSION_1) {
+      throw TProtocolException(TProtocolException::BAD_VERSION, "Bad version identifier");
+    }
+    messageType = (TMessageType)(sz & 0x000000ff);
+    result += readString(name);
+    result += readI32(seqid);
+  } else {
+    if (this->strict_read_) {
+      throw TProtocolException(TProtocolException::BAD_VERSION, "No version identifier... old protocol client in strict mode?");
+    } else {
+      // Handle pre-versioned input
+      int8_t type;
+      result += readStringBody(name, sz);
+      result += readByte(type);
+      messageType = (TMessageType)type;
+      result += readI32(seqid);
+    }
+  }
+  return result;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::readMessageEnd() {
+  return 0;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::readStructBegin(std::string& name) {
+  name = "";
+  return 0;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::readStructEnd() {
+  return 0;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::readFieldBegin(std::string& name,
+                                                      TType& fieldType,
+                                                      int16_t& fieldId) {
+  uint32_t result = 0;
+  int8_t type;
+  result += readByte(type);
+  fieldType = (TType)type;
+  if (fieldType == T_STOP) {
+    fieldId = 0;
+    return result;
+  }
+  result += readI16(fieldId);
+  return result;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::readFieldEnd() {
+  return 0;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::readMapBegin(TType& keyType,
+                                                    TType& valType,
+                                                    uint32_t& size) {
+  int8_t k, v;
+  uint32_t result = 0;
+  int32_t sizei;
+  result += readByte(k);
+  keyType = (TType)k;
+  result += readByte(v);
+  valType = (TType)v;
+  result += readI32(sizei);
+  if (sizei < 0) {
+    throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
+  } else if (this->container_limit_ && sizei > this->container_limit_) {
+    throw TProtocolException(TProtocolException::SIZE_LIMIT);
+  }
+  size = (uint32_t)sizei;
+  return result;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::readMapEnd() {
+  return 0;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::readListBegin(TType& elemType,
+                                                     uint32_t& size) {
+  int8_t e;
+  uint32_t result = 0;
+  int32_t sizei;
+  result += readByte(e);
+  elemType = (TType)e;
+  result += readI32(sizei);
+  if (sizei < 0) {
+    throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
+  } else if (this->container_limit_ && sizei > this->container_limit_) {
+    throw TProtocolException(TProtocolException::SIZE_LIMIT);
+  }
+  size = (uint32_t)sizei;
+  return result;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::readListEnd() {
+  return 0;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::readSetBegin(TType& elemType,
+                                                    uint32_t& size) {
+  int8_t e;
+  uint32_t result = 0;
+  int32_t sizei;
+  result += readByte(e);
+  elemType = (TType)e;
+  result += readI32(sizei);
+  if (sizei < 0) {
+    throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
+  } else if (this->container_limit_ && sizei > this->container_limit_) {
+    throw TProtocolException(TProtocolException::SIZE_LIMIT);
+  }
+  size = (uint32_t)sizei;
+  return result;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::readSetEnd() {
+  return 0;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::readBool(bool& value) {
+  uint8_t b[1];
+  this->trans_->readAll(b, 1);
+  value = *(int8_t*)b != 0;
+  return 1;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::readByte(int8_t& byte) {
+  uint8_t b[1];
+  this->trans_->readAll(b, 1);
+  byte = *(int8_t*)b;
+  return 1;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::readI16(int16_t& i16) {
+  uint8_t b[2];
+  this->trans_->readAll(b, 2);
+  i16 = *(int16_t*)b;
+  i16 = (int16_t)ntohs(i16);
+  return 2;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::readI32(int32_t& i32) {
+  uint8_t b[4];
+  this->trans_->readAll(b, 4);
+  i32 = *(int32_t*)b;
+  i32 = (int32_t)ntohl(i32);
+  return 4;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::readI64(int64_t& i64) {
+  uint8_t b[8];
+  this->trans_->readAll(b, 8);
+  i64 = *(int64_t*)b;
+  i64 = (int64_t)ntohll(i64);
+  return 8;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::readDouble(double& dub) {
+  BOOST_STATIC_ASSERT(sizeof(double) == sizeof(uint64_t));
+  BOOST_STATIC_ASSERT(std::numeric_limits<double>::is_iec559);
+
+  uint64_t bits;
+  uint8_t b[8];
+  this->trans_->readAll(b, 8);
+  bits = *(uint64_t*)b;
+  bits = ntohll(bits);
+  dub = bitwise_cast<double>(bits);
+  return 8;
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::readString(std::string& str) {
+  uint32_t result;
+  int32_t size;
+  result = readI32(size);
+  return result + readStringBody(str, size);
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::readBinary(std::string& str) {
+  return TBinaryProtocolT<Transport_>::readString(str);
+}
+
+template <class Transport_>
+uint32_t TBinaryProtocolT<Transport_>::readStringBody(std::string& str,
+                                                      int32_t size) {
+  uint32_t result = 0;
+
+  // Catch error cases
+  if (size < 0) {
+    throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
+  }
+  if (this->string_limit_ > 0 && size > this->string_limit_) {
+    throw TProtocolException(TProtocolException::SIZE_LIMIT);
+  }
+
+  // Catch empty string case
+  if (size == 0) {
+    str = "";
+    return result;
+  }
+
+  // Try to borrow first
+  const uint8_t* borrow_buf;
+  uint32_t got = size;
+  if ((borrow_buf = this->trans_->borrow(NULL, &got))) {
+    str.assign((const char*)borrow_buf, size);
+    this->trans_->consume(size);
+    return size;
+  }
+
+  // Use the heap here to prevent stack overflow for v. large strings
+  if (size > this->string_buf_size_ || this->string_buf_ == NULL) {
+    void* new_string_buf = std::realloc(this->string_buf_, (uint32_t)size);
+    if (new_string_buf == NULL) {
+      throw TProtocolException(TProtocolException::UNKNOWN,
+                               "Out of memory in TBinaryProtocolT::readString");
+    }
+    this->string_buf_ = (uint8_t*)new_string_buf;
+    this->string_buf_size_ = size;
+  }
+  this->trans_->readAll(this->string_buf_, size);
+  str = std::string((char*)this->string_buf_, size);
+  return (uint32_t)size;
+}
+
+}}} // apache::thrift::protocol
+
+#endif // #ifndef _THRIFT_PROTOCOL_TBINARYPROTOCOL_TCC_