Add fallback for endianess conversion
[collectd.git] / src / stdendian.h
1 /*
2  *   stdendian.h
3  *
4  *   This header defines the following endian macros as defined here:
5  *   http://austingroupbugs.net/view.php?id=162
6  *
7  *     BYTE_ORDER         this macro shall have a value equal to one
8  *                        of the *_ENDIAN macros in this header.
9  *     LITTLE_ENDIAN      if BYTE_ORDER == LITTLE_ENDIAN, the host
10  *                        byte order is from least significant to
11  *                        most significant.
12  *     BIG_ENDIAN         if BYTE_ORDER == BIG_ENDIAN, the host byte
13  *                        order is from most significant to least
14  *                        significant.
15  *
16  *   The following are defined as macros:
17  *
18  *     uint16_t bswap16(uint16_t x);
19  *     uint32_t bswap32(uint32_t x);
20  *     uint64_t bswap64(uint64_t x);
21
22  *     uint16_t htobe16(uint16_t x);
23  *     uint16_t htole16(uint16_t x);
24  *     uint16_t be16toh(uint16_t x);
25  *     uint16_t le16toh(uint16_t x);
26  *
27  *     uint32_t htobe32(uint32_t x);
28  *     uint32_t htole32(uint32_t x);
29  *     uint32_t be32toh(uint32_t x);
30  *     uint32_t le32toh(uint32_t x);
31  *
32  *     uint64_t htobe64(uint64_t x);
33  *     uint64_t htole64(uint64_t x);
34  *     uint64_t be64toh(uint64_t x);
35  *     uint64_t le64toh(uint64_t x);
36  *
37  *   The header defines the following macro for OpenCL compatibility
38  *   https://www.khronos.org/registry/cl/sdk/2.0/docs/man/xhtml/preprocessorDirectives.html
39  *
40  *     __ENDIAN_LITTLE__  if BYTE_ORDER == LITTLE_ENDIAN then this
41  *                        macro is present for OpenCL compatibility
42  *
43  *   The implementation provides a uniform interface to endian macros using only
44  *   system headers on recent Linux, Darwin, FreeBSD, Solaris and Windows systems. 
45  *
46  *   This approach is intended to avoid the need for preflight configure scripts.
47  *   An alternative approach would be to test compiler CPU architecture marcros.
48  *
49  *   This header has had *limited* testing on recent C11/C++11 compilers and is
50  *   based on the austin bug tracker interface, manpages, and headers present in
51  *   Linux, FreeBSD, Windows, Solaris and Darwin.
52  *
53  *   The header uses __builtin_bswapXX intrinsic with GCC/Clang (__GNUC__) on
54  *   platforms that do not provide bswap16, bswap32, bswap64 (Darwin)
55  *
56  *   Public Domain.
57  */
58
59 #if HAVE_STDINT_H
60 #include <stdint.h>
61 #endif
62
63 /* Linux / GLIBC */
64 #if defined(__linux__) || defined(__GLIBC__)
65 #include <endian.h>
66 #include <byteswap.h>
67 #define __ENDIAN_DEFINED        1
68 #define __BSWAP_DEFINED         1
69 #define __HOSTSWAP_DEFINED      1
70 #define _BYTE_ORDER             __BYTE_ORDER
71 #define _LITTLE_ENDIAN          __LITTLE_ENDIAN
72 #define _BIG_ENDIAN             __BIG_ENDIAN
73 #define bswap16(x)              bswap_16(x)
74 #define bswap32(x)              bswap_32(x)
75 #define bswap64(x)              bswap_64(x)
76 #endif /* __linux__ || __GLIBC__ */
77
78 /* BSD */
79 #if defined(__FreeBSD__) || defined(__NetBSD__) || \
80     defined(__DragonFly__) || defined(__OpenBSD__)
81 #include <sys/endian.h>
82 #define __ENDIAN_DEFINED        1
83 #define __BSWAP_DEFINED         1
84 #define __HOSTSWAP_DEFINED      1
85 #endif /* BSD */
86
87 /* Solaris */
88 #if defined (sun)
89 #include <sys/isa_defs.h>
90 #include <sys/byteorder.h>
91 #define bswap16(x)              BSWAP_16(x)
92 #define bswap32(x)              BSWAP_32(x)
93 #define bswap64(x)              BSWAP_64(x)
94 /* sun headers don't set a value for _LITTLE_ENDIAN or _BIG_ENDIAN */
95 #if defined(_LITTLE_ENDIAN)
96 #undef _LITTLE_ENDIAN
97 #define _LITTLE_ENDIAN          1234
98 #define _BIG_ENDIAN             4321
99 #define _BYTE_ORDER             _LITTLE_ENDIAN
100 #elif defined(_BIG_ENDIAN)
101 #undef _BIG_ENDIAN
102 #define _LITTLE_ENDIAN          1234
103 #define _BIG_ENDIAN             4321
104 #define _BYTE_ORDER             _BIG_ENDIAN
105 #endif
106 #define __ENDIAN_DEFINED        1
107 #endif /* sun */
108
109 /* Windows */
110 #if defined(_WIN32) || defined(_MSC_VER)
111 /* assumes all Microsoft targets are little endian */
112 #define _LITTLE_ENDIAN          1234
113 #define _BIG_ENDIAN             4321
114 #define _BYTE_ORDER             _LITTLE_ENDIAN
115 #define __ENDIAN_DEFINED        1
116 #endif /* _MSC_VER */
117
118 /* OS X */
119 #if defined(__APPLE__)
120 #include <machine/endian.h>
121 #define _BYTE_ORDER             BYTE_ORDER
122 #define _LITTLE_ENDIAN          LITTLE_ENDIAN
123 #define _BIG_ENDIAN             BIG_ENDIAN
124 #define __ENDIAN_DEFINED        1
125 #endif /* __APPLE__ */
126
127 /* OpenCL */
128 #if defined (__OPENCL_VERSION__)
129 #define _LITTLE_ENDIAN          1234
130 #define __BIG_ENDIAN            4321
131 #if defined (__ENDIAN_LITTLE__)
132 #define _BYTE_ORDER             _LITTLE_ENDIAN
133 #else
134 #define _BYTE_ORDER             _BIG_ENDIAN
135 #endif
136 #define bswap16(x)              as_ushort(as_uchar2(ushort(x)).s1s0)
137 #define bswap32(x)              as_uint(as_uchar4(uint(x)).s3s2s1s0)
138 #define bswap64(x)              as_ulong(as_uchar8(ulong(x)).s7s6s5s4s3s2s1s0)
139 #define __ENDIAN_DEFINED        1
140 #define __BSWAP_DEFINED         1
141 #endif
142
143 /* Unknown */
144 #if !__ENDIAN_DEFINED
145 #error Could not determine CPU byte order
146 #endif
147
148 /* POSIX - http://austingroupbugs.net/view.php?id=162 */
149 #ifndef BYTE_ORDER
150 #define BYTE_ORDER _BYTE_ORDER
151 #endif
152 #ifndef LITTLE_ENDIAN
153 #define LITTLE_ENDIAN _LITTLE_ENDIAN
154 #endif
155 #ifndef BIG_ENDIAN
156 #define BIG_ENDIAN _BIG_ENDIAN
157 #endif
158
159 /* OpenCL compatibility - define __ENDIAN_LITTLE__ on little endian systems */
160 #if _BYTE_ORDER == _LITTLE_ENDIAN
161 #if !defined (__ENDIAN_LITTLE__)
162 #define __ENDIAN_LITTLE__   1
163 #endif
164 #endif
165
166 /* Byte swap macros */
167 #if !__BSWAP_DEFINED
168
169 #ifndef bswap16
170 /* handle missing __builtin_bswap16 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52624 */
171 #if defined __GNUC__
172 /* define bswap16(x) __builtin_bswap16(x) */
173 #else
174 #define bswap16(x) ((uint16_t)((((uint16_t) (x) & 0xff00) >> 8) | \
175                                (((uint16_t) (x) & 0x00ff) << 8)))
176 #endif
177 #endif
178
179 #ifndef bswap32
180 #if defined __GNUC__
181 #define bswap32(x) __builtin_bswap32(x)
182 #else
183 #define bswap32(x) ((uint32_t)((((uint32_t) (x) & 0xff000000) >> 24) | \
184                                (((uint32_t) (x) & 0x00ff0000) >> 8) | \
185                                (((uint32_t) (x) & 0x0000ff00) << 8) | \
186                                (((uint32_t) (x) & 0x000000ff) << 24)))
187 #endif
188 #endif
189
190 #ifndef bswap64
191 #if defined __GNUC__
192 #define bswap64(x) __builtin_bswap64(x)
193 #else
194 #define bswap64(x) ((uint64_t)((((uint64_t) (x) & 0xff00000000000000ull) >> 56) | \
195                                (((uint64_t) (x) & 0x00ff000000000000ull) >> 40) | \
196                                (((uint64_t) (x) & 0x0000ff0000000000ull) >> 24) | \
197                                (((uint64_t) (x) & 0x000000ff00000000ull) >> 8) | \
198                                (((uint64_t) (x) & 0x00000000ff000000ull) << 8) | \
199                                (((uint64_t) (x) & 0x0000000000ff0000ull) << 24) | \
200                                (((uint64_t) (x) & 0x000000000000ff00ull) << 40) | \
201                                (((uint64_t) (x) & 0x00000000000000ffull) << 56)))
202 #endif
203 #endif
204
205 #endif
206
207 /* Host swap macros */
208 #ifndef __HOSTSWAP_DEFINED
209 #if __BYTE_ORDER == __LITTLE_ENDIAN
210 #define htobe16(x)              bswap16((x))
211 #define htole16(x)              ((uint16_t)(x))
212 #define be16toh(x)              bswap16((x))
213 #define le16toh(x)              ((uint16_t)(x))
214
215 #define htobe32(x)              bswap32((x))
216 #define htole32(x)              ((uint32_t)(x))
217 #define be32toh(x)              bswap32((x))
218 #define le32toh(x)              ((uint32_t)(x))
219
220 #define htobe64(x)              bswap64((x))
221 #define htole64(x)              ((uint64_t)(x))
222 #define be64toh(x)              bswap64((x))
223 #define le64toh(x)              ((uint64_t)(x))
224 #elif __BYTE_ORDER == __BIG_ENDIAN
225 #define htobe16(x)              ((uint16_t)(x))
226 #define htole16(x)              bswap16((x))
227 #define be16toh(x)              ((uint16_t)(x))
228 #define le16toh(x)              bswap16((x))
229
230 #define htobe32(x)              ((uint32_t)(x))
231 #define htole32(x)              bswap32((x))
232 #define be32toh(x)              ((uint32_t)(x))
233 #define le64toh(x)              bswap64((x))
234
235 #define htobe64(x)              ((uint64_t)(x))
236 #define htole64(x)              bswap64((x))
237 #define be64toh(x)              ((uint64_t)(x))
238 #define le32toh(x)              bswap32((x))
239 #endif
240 #endif
241
242