Remove bitfields, which are just a bit-addressed integer
[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(struct stream_pos *destp,
76 const struct type_class_float *dest_class,
77 struct stream_pos *srcp,
78 const struct type_class_float *src_class)
79 {
80 uint8_t sign;
81 int64_t exp;
82 uint64_t mantissa;
83
84 /* Read */
85 if (src->byte_order == LITTLE_ENDIAN) {
86 mantissa = ctf_uint_read(srcp, src_class->mantissa);
87 exp = ctf_int_read(srcp, src_class->exp);
88 sign = ctf_uint_read(srcp, src_class->sign);
89 } else {
90 sign = ctf_uint_read(srcp, src_class->sign);
91 exp = ctf_int_read(srcp, src_class->exp);
92 mantissa = ctf_uint_read(srcp, src_class->mantissa);
93 }
94 /* Write */
95 if (dest->byte_order == LITTLE_ENDIAN) {
96 ctf_uint_write(destp, dest_class->mantissa, mantissa);
97 ctf_int_write(destp, dest_class->exp, exp);
98 ctf_uint_write(destp, dest_class->sign, sign);
99 } else {
100 ctf_uint_write(destp, dest_class->sign, sign);
101 ctf_int_write(destp, dest_class->exp, exp);
102 ctf_uint_write(destp, dest_class->mantissa, mantissa);
103 }
104 }
105
106 void ctf_float_copy(struct stream_pos *dest, struct stream_pos *src,
107 const struct type_class_float *float_class)
108 {
109 align_pos(src, float_class->p.alignment);
110 align_pos(dest, float_class->p.alignment);
111 _ctf_float_copy(dest, float_class, src, float_class);
112 }
113
114 double ctf_double_read(struct stream_pos *srcp,
115 const struct type_class_float *float_class)
116 {
117 union doubleIEEE754 u;
118 struct ctf_float *dest_class = float_type_new(NULL,
119 DBL_MANT_DIG,
120 sizeof(double) * CHAR_BIT - DBL_MANT_DIG,
121 BYTE_ORDER,
122 __alignof__(double));
123 struct stream_pos destp;
124
125 align_pos(srcp, float_class->p.alignment);
126 init_pos(&destp, &u.bits);
127 _ctf_float_copy(&destp, dest_class, srcp, float_class);
128 float_type_free(dest_class);
129 return u.v;
130 }
131
132 void ctf_double_write(struct stream_pos *destp,
133 const struct type_class_float *float_class,
134 double v)
135 {
136 union doubleIEEE754 u;
137 struct ctf_float *src_class = float_type_new(NULL,
138 DBL_MANT_DIG,
139 sizeof(double) * CHAR_BIT - DBL_MANT_DIG,
140 BYTE_ORDER,
141 __alignof__(double));
142 struct stream_pos srcp;
143
144 u.v = v;
145 align_pos(destp, float_class->p.alignment);
146 init_pos(&srcp, &u.bits);
147 _ctf_float_copy(destp, float_class, &srcp, src_class);
148 float_type_free(src_class);
149 }
150
151 long double ctf_ldouble_read(struct stream_pos *srcp,
152 const struct type_class_float *float_class)
153 {
154 union ldoubleIEEE754 u;
155 struct ctf_float *dest_class = float_type_new(NULL,
156 LDBL_MANT_DIG,
157 sizeof(long double) * CHAR_BIT - LDBL_MANT_DIG,
158 BYTE_ORDER,
159 __alignof__(long double));
160 struct stream_pos destp;
161
162 align_pos(srcp, float_class->p.alignment);
163 init_pos(&destp, &u.bits);
164 _ctf_float_copy(&destp, dest_class, srcp, float_class);
165 float_type_free(dest_class);
166 return u.v;
167 }
168
169 void ctf_ldouble_write(struct stream_pos *destp,
170 const struct type_class_float *float_class,
171 long double v)
172 {
173 union ldoubleIEEE754 u;
174 struct ctf_float *src_class = float_type_new(NULL,
175 LDBL_MANT_DIG,
176 sizeof(long double) * CHAR_BIT - LDBL_MANT_DIG,
177 BYTE_ORDER,
178 __alignof__(long double));
179 struct stream_pos srcp;
180
181 u.v = v;
182 align_pos(destp, float_class->p.alignment);
183 init_pos(&srcp, &u.bits);
184 _ctf_float_copy(destp, float_class, &srcp, src_class);
185 float_type_free(src_class);
186 }
This page took 0.033446 seconds and 5 git commands to generate.