Use CHAR_BIT instead of 8 for float and string
[babeltrace.git] / formats / ctf / types / float.c
1 /*
2 * Common Trace Format
3 *
4 * Floating point read/write functions.
5 *
6 * Copyright (c) 2010 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 *
22 * Reference: ISO C99 standard 5.2.4
23 */
24
25 #include <babeltrace/ctf/types.h>
26 #include <glib.h>
27 #include <float.h> /* C99 floating point definitions */
28 #include <limits.h> /* C99 limits */
29 #include <endian.h>
30
31 /*
32 * This library is limited to binary representation of floating point values.
33 * Sign-extension of the exponents is assumed to keep the NaN, +inf, -inf
34 * values, but this should be double-checked (TODO).
35 */
36
37 /*
38 * Aliasing float/double and unsigned long is not strictly permitted by strict
39 * aliasing, but in practice type prunning is well supported, and this permits
40 * us to use per-word read/writes rather than per-byte.
41 */
42
43 #if defined(__GNUC__) || defined(__MINGW32__) || defined(_MSC_VER)
44 #define HAS_TYPE_PRUNING
45 #endif
46
47 #if (FLT_RADIX != 2)
48
49 #error "Unsupported floating point radix"
50
51 #endif
52
53 union doubleIEEE754 {
54 double v;
55 #ifdef HAS_TYPE_PRUNING
56 unsigned long bits[(sizeof(double) + sizeof(unsigned long) - 1) / sizeof(unsigned long)];
57 #else
58 unsigned char bits[sizeof(double)];
59 #endif
60 };
61
62 union ldoubleIEEE754 {
63 long double v;
64 #ifdef HAS_TYPE_PRUNING
65 unsigned long bits[(sizeof(long double) + sizeof(unsigned long) - 1) / sizeof(unsigned long)];
66 #else
67 unsigned char bits[sizeof(long double)];
68 #endif
69 };
70
71 struct pos_len {
72 size_t sign_start, exp_start, mantissa_start, len;
73 };
74
75 void ctf_float_copy(unsigned char *destp, const struct ctf_float *dest,
76 const unsigned char *src, const struct ctf_float *src)
77 {
78 struct pos_len destpos, srcpos;
79 union {
80 unsigned long long u;
81 long long s;
82 } tmp;
83
84 destpos.len = dest.exp_len + dest.mantissa_len;
85 if (dest.byte_order == LITTLE_ENDIAN) {
86 destpos.sign_start = destpos.len - 1;
87 destpos.exp_start = destpos.sign_start - dest->exp_len;
88 destpos.mantissa_start = 0;
89 } else {
90 destpos.sign_start = 0;
91 destpos.exp_start = 1;
92 destpos.mantissa_start = destpos.exp_start + dest->exp_len;
93 }
94
95 srcpos.len = src.exp_len + src.mantissa_len;
96 if (src.byte_order == LITTLE_ENDIAN) {
97 srcpos.sign_start = srcpos.len - 1;
98 srcpos.exp_start = srcpos.sign_start - src->exp_len;
99 srcpos.mantissa_start = 0;
100 } else {
101 srcpos.sign_start = 0;
102 srcpos.exp_start = 1;
103 srcpos.mantissa_start = srcpos.exp_start + src->exp_len;
104 }
105
106 /* sign */
107 tmp.u = ctf_bitfield_unsigned_read(ptr, srcpos.sign_start, 1,
108 src->byte_order);
109 ctf_bitfield_unsigned_write(&u.bits, destpos.sign_start, 1,
110 dest->byte_order, tmp.u);
111
112 /* mantissa (without leading 1). No sign extend. */
113 tmp.u = ctf_bitfield_unsigned_read(ptr, srcpos.mantissa_start,
114 src->mantissa_len - 1,
115 src->byte_order);
116 ctf_bitfield_unsigned_write(&u.bits, destpos.mantissa_start,
117 dest->mantissa_len - 1, dest->byte_order,
118 tmp.u);
119
120 /* exponent, with sign-extend. */
121 tmp.s = ctf_bitfield_signed_read(ptr, srcpos.exp_start, src->exp_len,
122 src->byte_order);
123 ctf_bitfield_signed_write(&u.bits, destpos.exp_start, dest->exp_len,
124 dest->byte_order, tmp.s);
125 }
126
127 double ctf_double_read(const unsigned char *ptr, const struct ctf_float *src)
128 {
129 union doubleIEEE754 u;
130 struct ctf_float dest = {
131 .exp_len = sizeof(double) * CHAR_BIT - DBL_MANT_DIG,
132 .mantissa_len = DBL_MANT_DIG,
133 .byte_order = BYTE_ORDER,
134 };
135
136 ctf_float_copy(&u.bits, &dest, ptr, src);
137 return u.v;
138 }
139
140 size_t ctf_double_write(unsigned char *ptr, const struct ctf_float *dest,
141 double v)
142 {
143 union doubleIEEE754 u;
144 struct ctf_float src = {
145 .exp_len = sizeof(double) * CHAR_BIT - DBL_MANT_DIG,
146 .mantissa_len = DBL_MANT_DIG,
147 .byte_order = BYTE_ORDER,
148 };
149
150 if (!ptr)
151 goto end;
152 u.v = v;
153 ctf_float_copy(ptr, dest, &u.bits, &src);
154 end:
155 return len;
156 }
157
158 long double ctf_ldouble_read(const unsigned char *ptr,
159 const struct ctf_float *src)
160 {
161 union ldoubleIEEE754 u;
162 struct ctf_float dest = {
163 .exp_len = sizeof(double) * CHAR_BIT - LDBL_MANT_DIG,
164 .mantissa_len = LDBL_MANT_DIG,
165 .byte_order = BYTE_ORDER,
166 };
167
168 ctf_float_copy(&u.bits, &dest, ptr, src);
169 return u.v;
170 }
171
172 size_t ctf_ldouble_write(unsigned char *ptr, const struct ctf_float *dest,
173 long double v)
174 {
175 union ldoubleIEEE754 u;
176 struct ctf_float src = {
177 .exp_len = sizeof(double) * CHAR_BIT - LDBL_MANT_DIG,
178 .mantissa_len = LDBL_MANT_DIG,
179 .byte_order = BYTE_ORDER,
180 };
181
182 if (!ptr)
183 goto end;
184 u.v = v;
185 ctf_float_copy(ptr, dest, &u.bits, &src);
186 end:
187 return len;
188 }
This page took 0.033133 seconds and 5 git commands to generate.