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

Reply via email to