1
2 /**
3 * Copyright (C) 2018-present MongoDB, Inc.
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the Server Side Public License, version 1,
7 * as published by MongoDB, Inc.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * Server Side Public License for more details.
13 *
14 * You should have received a copy of the Server Side Public License
15 * along with this program. If not, see
16 * <http://www.mongodb.com/licensing/server-side-public-license>.
17 *
18 * As a special exception, the copyright holders give permission to link the
19 * code of portions of this program with the OpenSSL library under certain
20 * conditions as described in each individual source file and distribute
21 * linked combinations including the program with the OpenSSL library. You
22 * must comply with the Server Side Public License in all respects for
23 * all of the code used other than as permitted herein. If you modify file(s)
24 * with this exception, you may extend this exception to your version of the
25 * file(s), but you are not obligated to do so. If you do not wish to do so,
26 * delete this exception statement from your version. If you delete this
27 * exception statement from all source files in the program, then also delete
28 * it in the license file.
29 */
30
31 #pragma once
32
33 #include <climits>
34 #include <cstdint>
35 #include <cstring>
36 #include <type_traits>
37
38 #include "mongo/base/static_assert.h"
39 #include "mongo/config.h"
40 #include "mongo/platform/decimal128.h"
41
42 #pragma push_macro("MONGO_UINT16_SWAB")
43 #pragma push_macro("MONGO_UINT32_SWAB")
44 #pragma push_macro("MONGO_UINT64_SWAB")
45 #pragma push_macro("htobe16")
46 #pragma push_macro("htobe32")
47 #pragma push_macro("htobe64")
48 #pragma push_macro("htole16")
49 #pragma push_macro("htole32")
50 #pragma push_macro("htole64")
51 #pragma push_macro("be16toh")
52 #pragma push_macro("be32toh")
53 #pragma push_macro("be64toh")
54 #pragma push_macro("le16toh")
55 #pragma push_macro("le32toh")
56 #pragma push_macro("le64toh")
57
58 #undef MONGO_UINT16_SWAB
59 #undef MONGO_UINT32_SWAB
60 #undef MONGO_UINT64_SWAB
61 #undef htobe16
62 #undef htobe32
63 #undef htobe64
64 #undef htole16
65 #undef htole32
66 #undef htole64
67 #undef be16toh
68 #undef be32toh
69 #undef be64toh
70 #undef le16toh
71 #undef le32toh
72 #undef le64toh
73
74 #define MONGO_LITTLE_ENDIAN 1234
75 #define MONGO_BIG_ENDIAN 4321
76
77 #if defined(_MSC_VER)
78 #include <cstdlib>
79 #define MONGO_UINT16_SWAB(v) _byteswap_ushort(v)
80 #define MONGO_UINT32_SWAB(v) _byteswap_ulong(v)
81 #define MONGO_UINT64_SWAB(v) _byteswap_uint64(v)
82 #elif defined(__clang__) && defined(__clang_major__) && defined(__clang_minor__) && \
83 (__clang_major__ >= 3) && (__clang_minor__ >= 1)
84 #if __has_builtin(__builtin_bswap16)
85 #define MONGO_UINT16_SWAB(v) __builtin_bswap16(v)
86 #endif
87 #if __has_builtin(__builtin_bswap32)
88 #define MONGO_UINT32_SWAB(v) __builtin_bswap32(v)
89 #endif
90 #if __has_builtin(__builtin_bswap64)
91 #define MONGO_UINT64_SWAB(v) __builtin_bswap64(v)
92 #endif
93 #elif defined(__GNUC__) && (__GNUC__ >= 4)
94 #if __GNUC__ >= 4 && defined(__GNUC_MINOR__) && __GNUC_MINOR__ >= 3
95 #define MONGO_UINT32_SWAB(v) __builtin_bswap32(v)
96 #define MONGO_UINT64_SWAB(v) __builtin_bswap64(v)
97 #endif
98 #if __GNUC__ >= 4 && defined(__GNUC_MINOR__) && __GNUC_MINOR__ >= 8
99 #define MONGO_UINT16_SWAB(v) __builtin_bswap16(v)
100 #endif
101 #elif defined(__sun)
102 #include <sys/byteorder.h>
103 #define MONGO_UINT16_SWAB(v) BSWAP_16(v)
104 #define MONGO_UINT32_SWAB(v) BSWAP_32(v)
105 #define MONGO_UINT64_SWAB(v) BSWAP_64(v)
106 #endif
107
108 #ifndef MONGO_UINT16_SWAB
109 #define MONGO_UINT16_SWAB(v) endian::bswap_slow16(v)
110 #endif
111
112 #ifndef MONGO_UINT32_SWAB
113 #define MONGO_UINT32_SWAB(v) endian::bswap_slow32(v)
114 #endif
115
116 #ifndef MONGO_UINT64_SWAB
117 #define MONGO_UINT64_SWAB(v) endian::bswap_slow64(v)
118 #endif
119
120 #if MONGO_CONFIG_BYTE_ORDER == MONGO_LITTLE_ENDIAN
121 #define htobe16(v) MONGO_UINT16_SWAB(v)
122 #define htobe32(v) MONGO_UINT32_SWAB(v)
123 #define htobe64(v) MONGO_UINT64_SWAB(v)
124 #define htole16(v) (v)
125 #define htole32(v) (v)
126 #define htole64(v) (v)
127 #define be16toh(v) MONGO_UINT16_SWAB(v)
128 #define be32toh(v) MONGO_UINT32_SWAB(v)
129 #define be64toh(v) MONGO_UINT64_SWAB(v)
130 #define le16toh(v) (v)
131 #define le32toh(v) (v)
132 #define le64toh(v) (v)
133 #elif MONGO_CONFIG_BYTE_ORDER == MONGO_BIG_ENDIAN
134 #define htobe16(v) (v)
135 #define htobe32(v) (v)
136 #define htobe64(v) (v)
137 #define htole16(v) MONGO_UINT16_SWAB(v)
138 #define htole32(v) MONGO_UINT32_SWAB(v)
139 #define htole64(v) MONGO_UINT64_SWAB(v)
140 #define be16toh(v) (v)
141 #define be32toh(v) (v)
142 #define be64toh(v) (v)
143 #define le16toh(v) MONGO_UINT16_SWAB(v)
144 #define le32toh(v) MONGO_UINT32_SWAB(v)
145 #define le64toh(v) MONGO_UINT64_SWAB(v)
146 #else
147 #error \
148 "The endianness of target architecture is unknown. " \
149 "Please define MONGO_CONFIG_BYTE_ORDER"
150 #endif
151
152 namespace mongo {
153 namespace endian {
154
bswap_slow16(uint16_t v)155 static inline uint16_t bswap_slow16(uint16_t v) {
156 return ((v & 0x00FF) << 8) | ((v & 0xFF00) >> 8);
157 }
158
bswap_slow32(uint32_t v)159 static inline uint32_t bswap_slow32(uint32_t v) {
160 return ((v & 0x000000FFUL) << 24) | ((v & 0x0000FF00UL) << 8) | ((v & 0x00FF0000UL) >> 8) |
161 ((v & 0xFF000000UL) >> 24);
162 }
163
bswap_slow64(uint64_t v)164 static inline uint64_t bswap_slow64(uint64_t v) {
165 return ((v & 0x00000000000000FFULL) << 56) | ((v & 0x000000000000FF00ULL) << 40) |
166 ((v & 0x0000000000FF0000ULL) << 24) | ((v & 0x00000000FF000000ULL) << 8) |
167 ((v & 0x000000FF00000000ULL) >> 8) | ((v & 0x0000FF0000000000ULL) >> 24) |
168 ((v & 0x00FF000000000000ULL) >> 40) | ((v & 0xFF00000000000000ULL) >> 56);
169 }
170
171 template <typename T>
172 struct ByteOrderConverter;
173
174 template <>
175 struct ByteOrderConverter<uint8_t> {
176 typedef uint8_t T;
177
178 inline static T nativeToBig(T t) {
179 return t;
180 }
181
182 inline static T bigToNative(T t) {
183 return t;
184 }
185
186 inline static T nativeToLittle(T t) {
187 return t;
188 }
189
190 inline static T littleToNative(T t) {
191 return t;
192 }
193 };
194
195 template <>
196 struct ByteOrderConverter<uint16_t> {
197 typedef uint16_t T;
198
199 inline static T nativeToBig(T t) {
200 return htobe16(t);
201 }
202
203 inline static T bigToNative(T t) {
204 return be16toh(t);
205 }
206
207 inline static T nativeToLittle(T t) {
208 return htole16(t);
209 }
210
211 inline static T littleToNative(T t) {
212 return le16toh(t);
213 }
214 };
215
216 template <>
217 struct ByteOrderConverter<uint32_t> {
218 typedef uint32_t T;
219
220 inline static T nativeToBig(T t) {
221 return htobe32(t);
222 }
223
224 inline static T bigToNative(T t) {
225 return be32toh(t);
226 }
227
228 inline static T nativeToLittle(T t) {
229 return htole32(t);
230 }
231
232 inline static T littleToNative(T t) {
233 return le32toh(t);
234 }
235 };
236
237 template <>
238 struct ByteOrderConverter<uint64_t> {
239 typedef uint64_t T;
240
241 inline static T nativeToBig(T t) {
242 return htobe64(t);
243 }
244
245 inline static T bigToNative(T t) {
246 return be64toh(t);
247 }
248
249 inline static T nativeToLittle(T t) {
250 return htole64(t);
251 }
252
253 inline static T littleToNative(T t) {
254 return le64toh(t);
255 }
256 };
257
258 template <>
259 struct ByteOrderConverter<int8_t> {
260 typedef int8_t T;
261
262 inline static T nativeToBig(T t) {
263 return t;
264 }
265
266 inline static T bigToNative(T t) {
267 return t;
268 }
269
270 inline static T nativeToLittle(T t) {
271 return t;
272 }
273
274 inline static T littleToNative(T t) {
275 return t;
276 }
277 };
278
279 template <>
280 struct ByteOrderConverter<int16_t> {
281 typedef int16_t T;
282
283 inline static T nativeToBig(T t) {
284 return htobe16(static_cast<uint16_t>(t));
285 }
286
287 inline static T bigToNative(T t) {
288 return be16toh(static_cast<uint16_t>(t));
289 }
290
291 inline static T nativeToLittle(T t) {
292 return htole16(static_cast<uint16_t>(t));
293 }
294
295 inline static T littleToNative(T t) {
296 return le16toh(static_cast<uint16_t>(t));
297 }
298 };
299
300 template <>
301 struct ByteOrderConverter<int32_t> {
302 typedef int32_t T;
303
304 inline static T nativeToBig(T t) {
305 return htobe32(static_cast<uint32_t>(t));
306 }
307
308 inline static T bigToNative(T t) {
309 return be32toh(static_cast<uint32_t>(t));
310 }
311
312 inline static T nativeToLittle(T t) {
313 return htole32(static_cast<uint32_t>(t));
314 }
315
316 inline static T littleToNative(T t) {
317 return le32toh(static_cast<uint32_t>(t));
318 }
319 };
320
321 template <>
322 struct ByteOrderConverter<int64_t> {
323 typedef int64_t T;
324
325 inline static T nativeToBig(T t) {
326 return htobe64(static_cast<uint64_t>(t));
327 }
328
329 inline static T bigToNative(T t) {
330 return be64toh(static_cast<uint64_t>(t));
331 }
332
333 inline static T nativeToLittle(T t) {
334 return htole64(static_cast<uint64_t>(t));
335 }
336
337 inline static T littleToNative(T t) {
338 return le64toh(static_cast<uint64_t>(t));
339 }
340 };
341
342 template <>
343 struct ByteOrderConverter<float> {
344 typedef float T;
345
346 inline static T nativeToBig(T t) {
347 MONGO_STATIC_ASSERT(sizeof(T) == sizeof(uint32_t));
348
349 uint32_t temp;
350 std::memcpy(&temp, &t, sizeof(t));
351 temp = htobe32(temp);
352 std::memcpy(&t, &temp, sizeof(t));
353 return t;
354 }
355
356 inline static T bigToNative(T t) {
357 uint32_t temp;
358 std::memcpy(&temp, &t, sizeof(t));
359 temp = be32toh(temp);
360 std::memcpy(&t, &temp, sizeof(t));
361 return t;
362 }
363
364 inline static T nativeToLittle(T t) {
365 uint32_t temp;
366 std::memcpy(&temp, &t, sizeof(t));
367 temp = htole32(temp);
368 std::memcpy(&t, &temp, sizeof(t));
369 return t;
370 }
371
372 inline static T littleToNative(T t) {
373 uint32_t temp;
374 std::memcpy(&temp, &t, sizeof(t));
375 temp = le32toh(temp);
376 std::memcpy(&t, &temp, sizeof(t));
377 return t;
378 }
379 };
380
381 template <>
382 struct ByteOrderConverter<double> {
383 typedef double T;
384
385 inline static T nativeToBig(T t) {
386 MONGO_STATIC_ASSERT(sizeof(T) == sizeof(uint64_t));
387
388 uint64_t temp;
389 std::memcpy(&temp, &t, sizeof(t));
390 temp = htobe64(temp);
391 std::memcpy(&t, &temp, sizeof(t));
392 return t;
393 }
394
395 inline static T bigToNative(T t) {
396 uint64_t temp;
397 std::memcpy(&temp, &t, sizeof(t));
398 temp = be64toh(temp);
399 std::memcpy(&t, &temp, sizeof(t));
400 return t;
401 }
402
403 inline static T nativeToLittle(T t) {
404 uint64_t temp;
405 std::memcpy(&temp, &t, sizeof(t));
406 temp = htole64(temp);
407 std::memcpy(&t, &temp, sizeof(t));
408 return t;
409 }
410
411 inline static T littleToNative(T t) {
412 uint64_t temp;
413 std::memcpy(&temp, &t, sizeof(t));
414 temp = le64toh(temp);
415 std::memcpy(&t, &temp, sizeof(t));
416 return t;
417 }
418 };
419
420 template <>
421 struct ByteOrderConverter<Decimal128::Value> {
422 typedef Decimal128::Value T;
423
424 inline static T nativeToBig(T t) {
425 ByteOrderConverter<uint64_t>::nativeToBig(t.low64);
426 ByteOrderConverter<uint64_t>::nativeToBig(t.high64);
427 return t;
428 }
429
430 inline static T bigToNative(T t) {
431 ByteOrderConverter<uint64_t>::bigToNative(t.low64);
432 ByteOrderConverter<uint64_t>::bigToNative(t.high64);
433 return t;
434 }
435
436 inline static T nativeToLittle(T t) {
437 ByteOrderConverter<uint64_t>::nativeToLittle(t.low64);
438 ByteOrderConverter<uint64_t>::nativeToLittle(t.high64);
439 return t;
440 }
441
442 inline static T littleToNative(T t) {
443 ByteOrderConverter<uint64_t>::littleToNative(t.low64);
444 ByteOrderConverter<uint64_t>::littleToNative(t.high64);
445 return t;
446 }
447 };
448
449 // Use a typemape to normalize non-fixed-width integral types to the associated fixed width
450 // types.
451
452 template <typename T>
453 struct IntegralTypeMap {
454 typedef T type;
455 };
456
457 template <>
458 struct IntegralTypeMap<signed char> {
459 MONGO_STATIC_ASSERT(CHAR_BIT == 8);
460 typedef int8_t type;
461 };
462
463 template <>
464 struct IntegralTypeMap<unsigned char> {
465 MONGO_STATIC_ASSERT(CHAR_BIT == 8);
466 typedef uint8_t type;
467 };
468
469 template <>
470 struct IntegralTypeMap<char> {
471 MONGO_STATIC_ASSERT(CHAR_BIT == 8);
472 typedef std::conditional<std::is_signed<char>::value, int8_t, uint8_t>::type type;
473 };
474
475 template <>
476 struct IntegralTypeMap<long long> {
477 MONGO_STATIC_ASSERT(sizeof(long long) == sizeof(int64_t));
478 typedef int64_t type;
479 };
480
481 template <>
482 struct IntegralTypeMap<unsigned long long> {
483 MONGO_STATIC_ASSERT(sizeof(unsigned long long) == sizeof(uint64_t));
484 typedef uint64_t type;
485 };
486
487 template <typename T>
488 inline T nativeToBig(T t) {
489 return ByteOrderConverter<typename IntegralTypeMap<T>::type>::nativeToBig(t);
490 }
491
492 template <typename T>
493 inline T bigToNative(T t) {
494 return ByteOrderConverter<typename IntegralTypeMap<T>::type>::bigToNative(t);
495 }
496
497 template <typename T>
498 inline T nativeToLittle(T t) {
499 return ByteOrderConverter<typename IntegralTypeMap<T>::type>::nativeToLittle(t);
500 }
501
502 template <typename T>
503 inline T littleToNative(T t) {
504 return ByteOrderConverter<typename IntegralTypeMap<T>::type>::littleToNative(t);
505 }
506
507 } // namespace endian
508 } // namespace mongo
509
510 #undef MONGO_UINT16_SWAB
511 #undef MONGO_UINT32_SWAB
512 #undef MONGO_UINT64_SWAB
513 #undef htobe16
514 #undef htobe32
515 #undef htobe64
516 #undef htole16
517 #undef htole32
518 #undef htole64
519 #undef be16toh
520 #undef be32toh
521 #undef be64toh
522 #undef le16toh
523 #undef le32toh
524 #undef le64toh
525
526 #pragma pop_macro("MONGO_UINT16_SWAB")
527 #pragma pop_macro("MONGO_UINT32_SWAB")
528 #pragma pop_macro("MONGO_UINT64_SWAB")
529 #pragma pop_macro("htobe16")
530 #pragma pop_macro("htobe32")
531 #pragma pop_macro("htobe64")
532 #pragma pop_macro("htole16")
533 #pragma pop_macro("htole32")
534 #pragma pop_macro("htole64")
535 #pragma pop_macro("be16toh")
536 #pragma pop_macro("be32toh")
537 #pragma pop_macro("be64toh")
538 #pragma pop_macro("le16toh")
539 #pragma pop_macro("le32toh")
540 #pragma pop_macro("le64toh")
541