Code

proto: Added support for marshaling double-precision values.
authorSebastian Harl <sh@tokkee.org>
Tue, 23 Dec 2014 17:16:13 +0000 (18:16 +0100)
committerSebastian Harl <sh@tokkee.org>
Tue, 23 Dec 2014 17:16:13 +0000 (18:16 +0100)
For this, determine the memory layout of doubles in 'configure' and then use
IEEE-754 big-endian encoding on the wire. For now, only little- and big-endian
IEEE-754 doubles are supported but that'll cover the vast majority of all
systems.

configure.ac
src/utils/proto.c
t/unit/utils/proto_test.c

index baf1137b530197b1689be9106ff4f9751b70377b..59f4ee7c413c0e5c5cdfeb2f66309d0e86d5d89e 100644 (file)
@@ -341,6 +341,66 @@ fi
 AC_SUBST([PROFILING_CFLAGS])
 AC_SUBST([PROFILING_LDFLAGS])
 
+ieee754_layout="unknown"
+AC_MSG_CHECKING([the memory layout of double precision values])
+AC_COMPILE_IFELSE(
+               [AC_LANG_PROGRAM(
+                       [[
+#include <string.h>
+#include <inttypes.h>
+                       ]],
+                       [[
+double d = 3.141592653e130;
+char c[8];
+if (sizeof(d) != 8)
+       return 2;
+memcpy(&c, &d, 8);
+if (c[0] == '\x04' && c[1] == '\x10' && c[2] == '\x1E' && c[3] == '\x66' &&
+       c[4] == '\x40' && c[5] == '\xA9' && c[6] == '\x06' && c[7] == '\x5B')
+       return 0;
+else
+       return 1;
+                       ]]
+               )],
+               [ieee754_layout="little-endian"], [ieee754_layout="unknown"])
+if test "x$ieee754_layout" = "xunknown"; then
+       AC_COMPILE_IFELSE(
+                       [AC_LANG_PROGRAM(
+                               [[
+#include <string.h>
+#include <inttypes.h>
+                               ]],
+                               [[
+double d = 3.141592653e130;
+char c[8];
+if (sizeof(d) != 8)
+       return 2;
+memcpy(&c, &d, 8);
+if (c[7] == '\x04' && c[6] == '\x10' && c[5] == '\x1E' && c[4] == '\x66' &&
+       c[3] == '\x40' && c[2] == '\xA9' && c[1] == '\x06' && c[0] == '\x5B')
+       return 0;
+else
+       return 1;
+                               ]]
+                       )],
+                       [ieee754_layout="big-endian"], [ieee754_layout="unknown"])
+fi
+AC_MSG_RESULT([IEEE-754 $ieee754_layout])
+
+AC_DEFINE([IEEE754_DOUBLE_LITTLE_ENDIAN], 1234,
+               [Identifier for IEEE-754 little-endian encoding of double precision values])
+AC_DEFINE([IEEE754_DOUBLE_BIG_ENDIAN], 4321,
+               [Identifier for IEEE-754 big-endian encoding of double precision values])
+if test "x$ieee754_layout" = "xlittle-endian"; then
+       AC_DEFINE([IEEE754_DOUBLE_BYTE_ORDER], 1234,
+                       [Define to 1 if double precision values use IEEE-754 little-endian encoding])
+else if test "x$ieee754_layout" = "xbig-endian"; then
+       AC_DEFINE([IEEE754_DOUBLE_BYTE_ORDER], 4321,
+                       [Define to 1 if double precision values use IEEE-754 little-endian encoding])
+else
+       AC_MSG_ERROR([Unknown memory layout of double precision values])
+fi; fi
+
 m4_divert_once([HELP_ENABLE], [
 Build dependencies:])
 
index cb88887d1f1313cd0797dcf9a5fbec9c63404277..af4215b8f987a32c5c0c264f9b5f43bbec56ed5f 100644 (file)
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#if HAVE_CONFIG_H
+#      include "config.h"
+#endif
+
 #include "core/data.h"
 #include "core/time.h"
 #include "utils/error.h"
 #include "utils/proto.h"
 
-#include <arpa/inet.h>
+#include <assert.h>
 #include <errno.h>
 
+#include <arpa/inet.h>
 #include <limits.h>
 
 #include <string.h>
@@ -62,13 +67,18 @@ marshal_int(char *buf, size_t buf_len, int64_t v)
 } /* marshal_int */
 
 static ssize_t
-marshal_double(char __attribute__((unused)) *buf,
-               size_t __attribute__((unused)) buf_len,
-               double __attribute__((unused)) v)
+marshal_double(char *buf, size_t buf_len, double v)
 {
-       /* XXX: find a good network representation */
-       errno = ENOTSUP;
-       return -1;
+       uint64_t t = 0;
+       assert(sizeof(v) == sizeof(t));
+       memcpy(&t, &v, sizeof(v));
+#if IEEE754_DOUBLE_BYTE_ORDER != IEEE754_DOUBLE_BIG_ENDIAN
+       t = (((int64_t)ntohl((int32_t)t)) << 32)
+               + ((int64_t)ntohl((int32_t)(t >> 32)));
+#endif
+       if (buf_len >= sizeof(t))
+               memcpy(buf, &t, sizeof(t));
+       return sizeof(t);
 } /* marshal_double */
 
 static ssize_t
index d0516b306b483cc4fe32c5cd502463014c9eff22..1ec0615fa33fd7a7f29c2796a9c2c369e92afebe 100644 (file)
@@ -49,6 +49,7 @@ START_TEST(test_marshal_data)
 
        regex_t dummy_re;
        int64_t int_values[] = { 47, 11, 23 };
+       double dec_values[] = { 47.11, .5 };
        char *string_values[] = { "foo", "abcd" };
 
        struct {
@@ -65,8 +66,8 @@ START_TEST(test_marshal_data)
                        12, INT_TYPE "\0\0\0\0\0\0\x12\x67",
                },
                {
-                       { SDB_TYPE_DECIMAL, { .integer = 4711 } },
-                       -1, NULL, /* not supported yet */
+                       { SDB_TYPE_DECIMAL, { .decimal = 3.141592653e130 } },
+                       12, DECIMAL_TYPE "\x5b\x6\xa9\x40\x66\x1e\x10\x4",
                },
                {
                        { SDB_TYPE_STRING, { .string = "some string" } },
@@ -92,6 +93,12 @@ START_TEST(test_marshal_data)
                        32, INT_ARRAY "\0\0\0\x3" "\0\0\0\0\0\0\0\x2f"
                                "\0\0\0\0\0\0\0\xb" "\0\0\0\0\0\0\0\x17"
                },
+               {
+                       { SDB_TYPE_DECIMAL | SDB_TYPE_ARRAY, { .array = {
+                               2, dec_values } } },
+                       24, DECIMAL_ARRAY "\0\0\0\x2" "\x40\x47\x8e\x14\x7a\xe1\x47\xae"
+                               "\x3f\xe0\0\0\0\0\0\0"
+               },
                {
                        { SDB_TYPE_STRING | SDB_TYPE_ARRAY, { .array = {
                                2, string_values } } },