Date: Wednesday, February 7, 2007 @ 11:03:08
Author: marc
Path: /cvsroot/carob/carob
Modified: src/SQLDataSerialization.cpp (1.41 -> 1.42)
test/40-Parameter-PreparedStatement/TestIEEE754.cpp (1.23 ->
1.24)
Reworked floating point serialization to fix big endian bug CAROB-118
and probably CAROB-116. Now at most one endianness swap is performed.
-----------------------------------------------------+
src/SQLDataSerialization.cpp | 152 +++++++++++-------
test/40-Parameter-PreparedStatement/TestIEEE754.cpp | 6
2 files changed, 99 insertions(+), 59 deletions(-)
Index: carob/src/SQLDataSerialization.cpp
diff -u carob/src/SQLDataSerialization.cpp:1.41
carob/src/SQLDataSerialization.cpp:1.42
--- carob/src/SQLDataSerialization.cpp:1.41 Tue Feb 6 20:08:38 2007
+++ carob/src/SQLDataSerialization.cpp Wed Feb 7 11:03:08 2007
@@ -102,22 +102,19 @@
return res;
}
-#ifdef CAROB_DEBUG_FLOAT
-namespace CarobNS {
-#else
namespace {
-#endif
// Float
/**
- * Relatively safe "reinterpret_cast" of an IEEE 754 float to its
- * uint32_t bit representation. Does NOT swap bytes in any way, so
- * endianness of the result is arch-specific. Endianness of floats
- * is typically the same as for integer types, but not granted.
+ * Relatively safe "reinterpret_cast" of a native IEEE 754 float to
+ * its uint32_t big endian representation. Usually returns a _big
+ * endian_ uint32_t since endianness of floats is usually the same
+ * as for integer types, even if not explicitely granted.
+ *
* @param f value to convert
*/
inline uint32_t
-floatToU32Bits(float f)
+floatToNetworkU32Bits(float f)
{
// "union casting" using { float; uint32_t; } or the simpler:
// return * (uint32_t *) &f;
@@ -128,63 +125,76 @@
// The more portable code below should not cost more than a couple
// of CPU cycles/converted float
const unsigned char *bytes = reinterpret_cast<const unsigned char *>(&f);
- return (uint32_t) bytes[3] << 24
- | (uint32_t) bytes[2] << 16
- | (uint32_t) bytes[1] << 8
- | (uint32_t) bytes[0];
+
+ // If the arch is all big endian (both for integers and floats),
+ // then there is no subtility and we return a native integer
+ // (big endian)
+
+ // If the arch is all little endian, then we returned a "reversed"
+ // result: big endian again.
+
+ return (uint32_t) bytes[0] << 24
+ | (uint32_t) bytes[1] << 16
+ | (uint32_t) bytes[2] << 8
+ | (uint32_t) bytes[3];
+
+ // if the arch is mixed-up, we fail.
+
}
+/**
+ * Big endian uint32_t to native float, see floatToNetworkU32Bits
+ */
inline float
-U32BitsToFloat(const uint32_t ui)
+networkU32BitsToFloat(const uint32_t ui)
{
float res;
unsigned char *f_bytes = reinterpret_cast<unsigned char *>(&res);
- f_bytes[3] = ui >> 24;
- f_bytes[2] = ui >> 16;
- f_bytes[1] = ui >> 8;
- f_bytes[0] = ui;
+ f_bytes[0] = ui >> 24;
+ f_bytes[1] = ui >> 16;
+ f_bytes[2] = ui >> 8;
+ f_bytes[3] = ui;
return res;
}
// Double
- /**
- * Relatively safe "reinterpret_cast" of an IEEE 754 double to its
- * uint64_t bit representation. Does NOT swap bytes in any way, so
- * endianness of the result is arch-specific. Endianness of doubles
- * is typically the same as for integer types, but not granted.
- * @param d value to convert
- */
+/**
+ * Native double to big endian uint64_t, see floatToNetworkU32Bits
+ */
inline uint64_t
-doubleToU64Bits(double d)
+doubleToNetworkU64Bits(double d)
{
const unsigned char *bytes = reinterpret_cast<const unsigned char *>(&d);
- return (uint64_t) bytes[7] << 56
- | (uint64_t) bytes[6] << 48
- | (uint64_t) bytes[5] << 40
- | (uint64_t) bytes[4] << 32
- | (uint64_t) bytes[3] << 24
- | (uint64_t) bytes[2] << 16
- | (uint64_t) bytes[1] << 8
- | (uint64_t) bytes[0];
+ return (uint64_t) bytes[0] << 56
+ | (uint64_t) bytes[1] << 48
+ | (uint64_t) bytes[2] << 40
+ | (uint64_t) bytes[3] << 32
+ | (uint64_t) bytes[4] << 24
+ | (uint64_t) bytes[5] << 16
+ | (uint64_t) bytes[6] << 8
+ | (uint64_t) bytes[7];
}
+/**
+ * Big endian uint64_t to native double, see floatToNetworkU32Bits
+ */
inline double
-U64BitsToDouble(const uint64_t ui)
+networkU64BitsToDouble(const uint64_t ui)
{
double res;
unsigned char *d_bytes = reinterpret_cast<unsigned char *>(&res);
- d_bytes[7] = ui >> 56;
- d_bytes[6] = ui >> 48;
- d_bytes[5] = ui >> 40;
- d_bytes[4] = ui >> 32;
- d_bytes[3] = ui >> 24;
- d_bytes[2] = ui >> 16;
- d_bytes[1] = ui >> 8;
- d_bytes[0] = ui;
+ d_bytes[0] = ui >> 56;
+ d_bytes[1] = ui >> 48;
+ d_bytes[2] = ui >> 40;
+ d_bytes[3] = ui >> 32;
+ d_bytes[4] = ui >> 24;
+ d_bytes[5] = ui >> 16;
+ d_bytes[6] = ui >> 8;
+ d_bytes[7] = ui;
return res;
}
@@ -205,15 +215,14 @@
throw (SocketIOException, UnexpectedException)
{
ResultSetDataType res;
- int32_t intRead;
+ uint32_t bigEndianInt;
- input >> intRead; // this does call ntohl()
+ input.readBytes(4, reinterpret_cast<java_byte *>(&bigEndianInt));
if (floats_inverted_endianness)
- // obviously cannot use ntohl() to swap unconditionnally!
throw NotImplementedException(L"Inverted endianness Not Implemented
Yet");
- else
- res.as_float = U32BitsToFloat(intRead); // sign casting here
+ else // takes care of cast + endianness swap if needed
+ res.as_float = networkU32BitsToFloat(bigEndianInt);
return res;
}
@@ -228,17 +237,15 @@
ResultSetDataType doubleDeserializer(const DriverSocket& input)
throw (SocketIOException, UnexpectedException)
{
- // code duplicated with floatDeserializer (sorry, no template)
- // -> go and see the numerous implementation comments there
ResultSetDataType res;
- int64_t intRead;
+ uint64_t bigEndianInt;
- input >> intRead; // this does call ntohll()
+ input.readBytes(8, reinterpret_cast<java_byte *>(&bigEndianInt));
if (floats_inverted_endianness)
throw NotImplementedException(L"Inverted endianness Not Implemented
Yet");
- else
- res.as_double = U64BitsToDouble(intRead); // sign casting here
+ else // takes care of cast + endianness swap if needed
+ res.as_double = networkU64BitsToDouble(bigEndianInt);
return res;
}
@@ -356,11 +363,42 @@
}
}
+#ifdef CAROB_DEBUG_FLOAT
+namespace CarobNS {
+#else
namespace {
+#endif
+
+// See floatToNetworkU32Bits() above
+uint32_t F2I(const float f)
+{
+ uint32_t result;
+ const unsigned char *fbytes = reinterpret_cast<const unsigned char *>(&f);
+ unsigned char *ibytes = reinterpret_cast<unsigned char *>(&result);
+
+ for (int i=0; i<4; i++)
+ ibytes[i] = fbytes[i];
+
+ return result;
+}
-// shortcuts
-#define F2I(f) floatToU32Bits(f)
-#define D2I(d) doubleToU64Bits(d);
+// See floatToNetworkU32Bits() above
+uint64_t D2I(const double f)
+{
+ uint64_t result;
+ const unsigned char *fbytes = reinterpret_cast<const unsigned char *>(&f);
+ unsigned char *ibytes = reinterpret_cast<unsigned char *>(&result);
+
+ for (int i=0; i<8; i++)
+ ibytes[i] = fbytes[i];
+
+ return result;
+}
+
+} // unnamed or CarobNS namespace
+
+
+namespace {
bool
floats_little_endianness()
Index: carob/test/40-Parameter-PreparedStatement/TestIEEE754.cpp
diff -u carob/test/40-Parameter-PreparedStatement/TestIEEE754.cpp:1.23
carob/test/40-Parameter-PreparedStatement/TestIEEE754.cpp:1.24
--- carob/test/40-Parameter-PreparedStatement/TestIEEE754.cpp:1.23 Thu Jan
25 22:42:28 2007
+++ carob/test/40-Parameter-PreparedStatement/TestIEEE754.cpp Wed Feb 7
11:03:08 2007
@@ -48,9 +48,11 @@
#ifdef CAROB_DEBUG_FLOAT
namespace CarobNS {
-uint32_t floatToU32Bits(float f);
-uint64_t doubleToU64Bits(double d);
+uint32_t F2I(float f);
+uint64_t D2I(double d);
}
+#define floatToU32Bits(f) F2I(f)
+#define doubleToU64Bits(d) D2I(d)
#endif
using namespace CarobNS;
_______________________________________________
Carob-commits mailing list
[email protected]
https://forge.continuent.org/mailman/listinfo/carob-commits