Browse Source

lib/stream: add float/double <-> IEEE-754 single/double mux/demuxers

* stream.{c,h}: Add stream_get{f,d} and stream_put{f,d}) demux and muxers to
  safely convert between big-endian IEEE-754 single and double binary
  format, as used in IETF RFCs, and C99.  Implementation depends on host
  using __STDC_IEC_559__, which should be everything we care about.  Should
  correctly error out otherwise.

  Thanks to Aidan Delaney <aidan@phoric.eu> and Olivier Dugeon for pointing
  out the __STDC_IEC_559__ macro.

  Update: GCC does not per se set __STDC_IEC_559__, so also test for
  __GCC_IEC_559 >= 1.
Paul Jakma 6 years ago
parent
commit
d41e7b975b
2 changed files with 72 additions and 0 deletions
  1. 66 0
      lib/stream.c
  2. 6 0
      lib/stream.h

+ 66 - 0
lib/stream.c

@@ -22,6 +22,8 @@
 
 #include <zebra.h>
 #include <stddef.h>
+/* primarily for __STDC_IEC_559__ with clang */
+#include <features.h>
 
 #include "stream.h"
 #include "memory.h"
@@ -493,6 +495,38 @@ stream_get_ipv4 (struct stream *s)
   return l;
 }
 
+float
+stream_getf (struct stream *s)
+{
+#if defined(__STDC_IEC_559__) || __GCC_IEC_559 >= 1
+/* we can safely assume 'float' is in the single precision
+   IEC 60559 binary format in host order */
+  union {
+    float r;
+    uint32_t d;
+  } u;
+  u.d = stream_getl (s);
+  return u.r;
+#else
+#error "Please supply stream_getf implementation for this platform"
+#endif
+}
+
+double
+stream_getd (struct stream *s)
+{
+#if defined(__STDC_IEC_559__) || __GCC_IEC_559 >= 1
+  union {
+    double r;
+    uint64_t d;
+  } u;
+  u.d = stream_getq (s);
+  return u.r;
+#else
+#error "Please supply stream_getd implementation for this platform"
+#endif
+}
+
 /* Copy to source to stream.
  *
  * XXX: This uses CHECK_SIZE and hence has funny semantics -> Size will wrap
@@ -601,6 +635,38 @@ stream_putq (struct stream *s, uint64_t q)
   return 8;
 }
 
+int
+stream_putf (struct stream *s, float f)
+{
+#if defined(__STDC_IEC_559__) || __GCC_IEC_559 >= 1
+/* we can safely assume 'float' is in the single precision
+   IEC 60559 binary format in host order */
+  union {
+    float i;
+    uint32_t o;
+  } u;
+  u.i = f;
+  return stream_putl (s, u.o);
+#else
+#error "Please supply stream_putf implementation for this platform"
+#endif
+}
+
+int
+stream_putd (struct stream *s, double d)
+{
+#if defined(__STDC_IEC_559__) || __GCC_IEC_559 >= 1
+  union {
+    double i;
+    uint64_t o;
+  } u;
+  u.i = d;
+  return stream_putq (s, u.o);
+#else
+#error "Please supply stream_putd implementation for this platform"
+#endif
+}
+
 int
 stream_putc_at (struct stream *s, size_t putp, u_char c)
 {

+ 6 - 0
lib/stream.h

@@ -186,6 +186,12 @@ extern uint64_t stream_getq (struct stream *);
 extern uint64_t stream_getq_from (struct stream *, size_t);
 extern u_int32_t stream_get_ipv4 (struct stream *);
 
+/* IEEE-754 floats */
+extern float stream_getf (struct stream *);
+extern double stream_getd (struct stream *);
+extern int stream_putf (struct stream *, float);
+extern int stream_putd (struct stream *, double);
+
 #undef stream_read
 #undef stream_write