Crazy byteswapping thrift patches from david reiss
Reviewed By: ninjitsu
Test Plan: bswap64, holla holla
git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665098 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/cpp/configure.ac b/lib/cpp/configure.ac
index 9802096..a6d61e8 100644
--- a/lib/cpp/configure.ac
+++ b/lib/cpp/configure.ac
@@ -54,6 +54,8 @@
AC_CHECK_HEADERS([unistd.h])
+AC_CHECK_HEADERS([endian.h])
+
AC_C_INLINE
AX_BOOST_BASE([1.33.1])
diff --git a/lib/cpp/src/TLogging.h b/lib/cpp/src/TLogging.h
index e814e41..15c9c06 100644
--- a/lib/cpp/src/TLogging.h
+++ b/lib/cpp/src/TLogging.h
@@ -7,14 +7,25 @@
#ifndef _THRIFT_LOGGING_H
#define _THRIFT_LOGGING_H 1
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
/**
* Contains utility macros for debugging and logging.
*
* @author Aditya Agarwal
*/
+#ifndef HAVE_CLOCK_GETTIME
#include <time.h>
+#else
+#include <sys/time.h>
+#endif
+
+#ifdef HAVE_STDINT_H
#include <stdint.h>
+#endif
/**
* T_GLOBAL_DEBUGGING_LEVEL = 0: all debugging turned off, debug macros undefined
diff --git a/lib/cpp/src/Thrift.h b/lib/cpp/src/Thrift.h
index d024ad5..2cb656b 100644
--- a/lib/cpp/src/Thrift.h
+++ b/lib/cpp/src/Thrift.h
@@ -7,8 +7,14 @@
#ifndef _THRIFT_THRIFT_H_
#define _THRIFT_THRIFT_H_ 1
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <netinet/in.h>
+#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
+#endif
#include <string>
#include <map>
#include <list>
diff --git a/lib/cpp/src/protocol/TBinaryProtocol.cpp b/lib/cpp/src/protocol/TBinaryProtocol.cpp
index 544ef88..5116e86 100644
--- a/lib/cpp/src/protocol/TBinaryProtocol.cpp
+++ b/lib/cpp/src/protocol/TBinaryProtocol.cpp
@@ -6,8 +6,50 @@
#include "TBinaryProtocol.h"
+#include <boost/static_assert.hpp>
+
using std::string;
+// Use this to get around strict aliasing rules.
+// For example, uint64_t i = bitwise_cast<uint64_t>(returns_double());
+// The most obvious implementation is to just cast a pointer,
+// but that doesn't work.
+// For a pretty in-depth explanation of the problem, see
+// http://www.cellperformance.com/mike_acton/2006/06/ (...)
+// understanding_strict_aliasing.html
+template <typename To, typename From>
+static inline To bitwise_cast(From from) {
+ BOOST_STATIC_ASSERT(sizeof(From) == sizeof(To));
+
+ // BAD!!! These are all broken with -O2.
+ //return *reinterpret_cast<To*>(&from); // BAD!!!
+ //return *static_cast<To*>(static_cast<void*>(&from)); // BAD!!!
+ //return *(To*)(void*)&from; // BAD!!!
+
+ // Super clean and paritally blessed by section 3.9 of the standard.
+ //unsigned char c[sizeof(from)];
+ //memcpy(c, &from, sizeof(from));
+ //To to;
+ //memcpy(&to, c, sizeof(c));
+ //return to;
+
+ // Slightly more questionable.
+ // Same code emitted by GCC.
+ //To to;
+ //memcpy(&to, &from, sizeof(from));
+ //return to;
+
+ // Technically undefined, but almost universally supported,
+ // and the most efficient implementation.
+ union {
+ From f;
+ To t;
+ } u;
+ u.f = from;
+ return u.t;
+}
+
+
namespace facebook { namespace thrift { namespace protocol {
uint32_t TBinaryProtocol::writeMessageBegin(const std::string& name,
@@ -113,17 +155,12 @@
}
uint32_t TBinaryProtocol::writeDouble(const double dub) {
- uint8_t b[8];
- uint8_t* d = (uint8_t*)&dub;
- b[0] = d[7];
- b[1] = d[6];
- b[2] = d[5];
- b[3] = d[4];
- b[4] = d[3];
- b[5] = d[2];
- b[6] = d[1];
- b[7] = d[0];
- trans_->write((uint8_t*)b, 8);
+ 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);
+ trans_->write((uint8_t*)&bits, 8);
return 8;
}
@@ -291,18 +328,15 @@
}
uint32_t TBinaryProtocol::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];
- uint8_t d[8];
trans_->readAll(b, 8);
- d[0] = b[7];
- d[1] = b[6];
- d[2] = b[5];
- d[3] = b[4];
- d[4] = b[3];
- d[5] = b[2];
- d[6] = b[1];
- d[7] = b[0];
- dub = *(double*)d;
+ bits = *(uint64_t*)b;
+ bits = ntohll(bits);
+ dub = bitwise_cast<double>(bits);
return 8;
}
diff --git a/lib/cpp/src/protocol/TProtocol.h b/lib/cpp/src/protocol/TProtocol.h
index 6264bb6..47d74f8 100644
--- a/lib/cpp/src/protocol/TProtocol.h
+++ b/lib/cpp/src/protocol/TProtocol.h
@@ -21,12 +21,24 @@
using facebook::thrift::transport::TTransport;
+#ifdef HAVE_ENDIAN_H
+#include <endian.h>
+#endif
+
#if __BYTE_ORDER == __BIG_ENDIAN
-#define ntohll(n) (n)
-#define htonll(n) (n)
-#else
-#define ntohll(n) ( (((unsigned long long)ntohl(n)) << 32) + ntohl(n >> 32) )
-#define htonll(n) ( (((unsigned long long)htonl(n)) << 32) + htonl(n >> 32) )
+# define ntohll(n) (n)
+# define htonll(n) (n)
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+# if defined(__GNUC__) && defined(__GLIBC__)
+# include <byteswap.h>
+# define ntohll(n) bswap_64(n)
+# define htonll(n) bswap_64(n)
+# else /* GNUC & GLIBC */
+# define ntohll(n) ( (((unsigned long long)ntohl(n)) << 32) + ntohl(n >> 32) )
+# define htonll(n) ( (((unsigned long long)htonl(n)) << 32) + htonl(n >> 32) )
+# endif /* GNUC & GLIBC */
+#else /* __BYTE_ORDER */
+# error "Can't define htonll or ntohll!"
#endif
/**
diff --git a/lib/cpp/src/transport/TFileTransport.cpp b/lib/cpp/src/transport/TFileTransport.cpp
index aafdc21..84ea60d 100644
--- a/lib/cpp/src/transport/TFileTransport.cpp
+++ b/lib/cpp/src/transport/TFileTransport.cpp
@@ -20,6 +20,9 @@
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
#include <iostream>
#include <sys/stat.h>